在 PHP 中链接静态方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/125268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:33:57  来源:igfitidea点击:

Chaining Static Methods in PHP?

phpoopmethod-chaining

提问by Wilco

Is it possible to chain static methods together using a static class? Say I wanted to do something like this:

是否可以使用静态类将静态方法链接在一起?说我想做这样的事情:

$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();

. . . and obviously I would want $value to be assigned the number 14. Is this possible?

. . . 显然我希望 $value 被分配数字 14。这可能吗?

Update: It doesn't work (you can't return "self" - it's not an instance!), but this is where my thoughts have taken me:

更新:它不起作用(你不能返回“自我”——这不是一个实例!),但这就是我的想法:

class TestClass {
    public static $currentValue;

    public static function toValue($value) {
        self::$currentValue = $value;
    }

    public static function add($value) {
        self::$currentValue = self::$currentValue + $value;
        return self;
    }

    public static function subtract($value) {
        self::$currentValue = self::$currentValue - $value;
        return self;
    }

    public static function result() {
        return self::$value;
    }
}

After working that out, I think it would just make more sense to simply work with a class instance rather than trying to chain static function calls (which doesn't look possible, unless the above example could be tweaked somehow).

在解决了这个问题之后,我认为简单地使用类实例而不是尝试链接静态函数调用会更有意义(这看起来不可能,除非上面的例子可以以某种方式进行调整)。

采纳答案by Mathew Byrne

I like the solution provided by Camilo above, essentially since all you're doing is altering the value of a static member, and since you do want chaining (even though it's only syntatic sugar), then instantiating TestClass is probably the best way to go.

我喜欢上面 Camilo 提供的解决方案,基本上因为你所做的只是改变静态成员的值,而且你确实想要链接(即使它只是语法糖),那么实例化 TestClass 可能是最好的方法.

I'd suggest a Singleton pattern if you want to restrict instantiation of the class:

如果您想限制类的实例化,我建议使用单例模式:

class TestClass
{   
    public static $currentValue;

    private static $_instance = null;

    private function __construct () { }

    public static function getInstance ()
    {
        if (self::$_instance === null) {
            self::$_instance = new self;
        }

        return self::$_instance;
    }

    public function toValue($value) {
        self::$currentValue = $value;
        return $this;
    }

    public function add($value) {
        self::$currentValue = self::$currentValue + $value;
        return $this;
    }

    public function subtract($value) {
        self::$currentValue = self::$currentValue - $value;
        return $this;
    }

    public function result() {
        return self::$currentValue;
    }
}

// Example Usage:
$result = TestClass::getInstance ()
    ->toValue(5)
    ->add(3)
    ->subtract(2)
    ->add(8)
    ->result();

回答by Ariful Islam

class oop{
    public static $val;

    public static function add($var){
        static::$val+=$var;
        return new static;
    }

    public static function sub($var){
        static::$val-=$var;
        return new static;
    }

    public static function out(){
        return static::$val;
    }

    public static function init($var){
        static::$val=$var;
        return new static;      
    }
}

echo oop::init(5)->add(2)->out();

回答by sectus

Little crazy code on php5.3... just for fun.

php5.3 上的小疯狂代码......只是为了好玩。

namespace chaining;
class chain
    {
    static public function one()
        {return get_called_class();}

    static public function two()
        {return get_called_class();}
    }

${${${${chain::one()} = chain::two()}::one()}::two()}::one();

回答by sectus

With php7 you will be able to use desired syntax because of new Uniform Variable Syntax

使用 php7,您将能够使用所需的语法,因为新的统一变量语法

<?php

abstract class TestClass {

    public static $currentValue;

    public static function toValue($value) {
        self::$currentValue = $value;
        return __CLASS__;
    }

    public static function add($value) {
        self::$currentValue = self::$currentValue + $value;
        return __CLASS__;
    }

    public static function subtract($value) {
        self::$currentValue = self::$currentValue - $value;
        return __CLASS__;
    }

    public static function result() {
        return self::$currentValue;
    }

}

$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();
echo $value;

Demo

演示

回答by Camilo Díaz Repka

If toValue(x) returns an object, you could do like this:

如果 toValue(x) 返回一个对象,你可以这样做:

$value = TestClass::toValue(5)->add(3)->substract(2)->add(8);

Providing that toValue returns a new instance of the object, and each next method mutates it, returning an instance of $this.

提供 toValue 返回对象的一个​​新实例,每个 next 方法都会改变它,返回 $this 的一个实例。

回答by Phobis

You could always use the First method as a static and the remaining as instance methods:

您始终可以将 First 方法用作静态方法,将其余方法用作实例方法:

$value = Math::toValue(5)->add(3)->subtract(2)->add(8)->result();

Or better yet:

或者更好:

 $value = Math::eval(Math::value(5)->add(3)->subtract(2)->add(8));

class Math {
     public $operation;
     public $operationValue;
     public $args;
     public $allOperations = array();

     public function __construct($aOperation, $aValue, $theArgs)
     {
       $this->operation = $aOperation;
       $this->operationValue = $aValue;
       $this->args = $theArgs;
     }

     public static function eval($math) {
       if(strcasecmp(get_class($math), "Math") == 0){
            $newValue = $math->operationValue;
            foreach ($math->allOperations as $operationKey=>$currentOperation) {
                switch($currentOperation->operation){
                    case "add":
                         $newvalue = $currentOperation->operationValue + $currentOperation->args;
                         break;
                    case "subtract":
                         $newvalue = $currentOperation->operationValue - $currentOperation->args;
                         break;
                }
            }
            return $newValue;
       }
       return null;
     }

     public function add($number){
         $math = new Math("add", null, $number);
         $this->allOperations[count($this->allOperations)] &= $math;
         return $this;
     }

     public function subtract($number){
         $math = new Math("subtract", null, $number);
         $this->allOperations[count($this->allOperations)] &= $math;
         return $this;
     }

     public static function value($number){
         return new Math("value", $number, null);
     }
 }

Just an FYI.. I wrote this off the top of my head (right here on the site). So, it may not run, but that is the idea. I could have also did a recursive method call to eval, but I thought this may be simpler. Please let me know if you would like me to elaborate or provide any other help.

仅供参考......我把这个写在我的头上(就在网站上)。因此,它可能无法运行,但这就是想法。我也可以对 eval 进行递归方法调用,但我认为这可能更简单。如果您希望我详细说明或提供任何其他帮助,请告诉我。

回答by George Garchagudashvili

This is more accurate, easier, and read-friendly (allows code-completion)

这更准确、更容易、更易于阅读(允许代码完成)

class Calculator
{   
    public static $value = 0;

    protected static $onlyInstance;

    protected function __construct () 
    {
        // disable creation of public instances 
    }

    protected static function getself()
    {
        if (static::$onlyInstance === null) 
        {
            static::$onlyInstance = new Calculator;
        }

        return static::$onlyInstance;
    }

    /**
     * add to value
     * @param numeric $num 
     * @return \Calculator
     */
    public static function add($num) 
    {
        static::$value += $num;
        return static::getself();
    }

    /**
     * substruct
     * @param string $num
     * @return \Calculator
     */
    public static function subtract($num) 
    {
        static::$value -= $num;
        return static::getself();
    }

    /**
     * multiple by
     * @param string $num
     * @return \Calculator
     */
    public static function multiple($num) 
    {
        static::$value *= $num;
        return static::getself();
    }

    /**
     * devide by
     * @param string $num
     * @return \Calculator
     */
    public static function devide($num) 
    {
        static::$value /= $num;
        return static::getself();
    }

    public static function result()
    {
        return static::$value;
    }
}

Example:

例子:

echo Calculator::add(5)
        ->subtract(2)
        ->multiple(2.1)
        ->devide(10)
    ->result();

result: 0.63

结果:0.63

回答by kdion4891

People are overcomplicating this like crazy.

人们疯狂地过度复杂化。

Check this out:

看一下这个:

class OopClass
{
    public $first;
    public $second;
    public $third;

    public static function make($first)
    {
        return new OopClass($first);
    }

    public function __construct($first)
    {
        $this->first = $first;
    }

    public function second($second)
    {
        $this->second = $second;
        return $this;
    }

    public function third($third)
    {
        $this->third = $third;
        return $this;
    }
}

Usage:

用法:

OopClass::make('Hello')->second('To')->third('World');

回答by sanmai

Technically you can call a static method on an instance like $object::method()in PHP 7+, so returning a new instance should work as a replacement for return self. And indeed it works.

从技术上讲,您可以像$object::method()在 PHP 7+ 中那样在实例上调用静态方法,因此返回一个新实例应该可以替代return self. 确实有效。

final class TestClass {
    public static $currentValue;

    public static function toValue($value) {
        self::$currentValue = $value;
        return new static();
    }

    public static function add($value) {
        self::$currentValue = self::$currentValue + $value;
        return new static();
    }

    public static function subtract($value) {
        self::$currentValue = self::$currentValue - $value;
        return new static();
    }

    public static function result() {
        return self::$currentValue;
    }
}

$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();

var_dump($value);

Outputs int(14).

输出int(14)

This about same as returning __CLASS__as used in other answer. I rather hope no-one ever decides to actually use these forms of API, but you asked for it.

这与其他答案中__CLASS__使用的返回大致相同。我宁愿希望没有人决定实际使用这些形式的 API,但您要求这样做。

回答by dirtside

In a nutshell... no. :) The resolution operator (::) would work for the TetsClass::toValue(5) part, but everything after that will just give a syntax error.

简而言之……不。:) 解析运算符 (::) 将适用于 TetsClass::toValue(5) 部分,但之后的所有内容只会出现语法错误。

Once namespaces are implemented in 5.3, you can have "chained" :: operators, but all that'll do is drill down through the namespace tree; it won't be possible to have methods in the middle of things like this.

一旦命名空间在 5.3 中实现,您就可以“链接” :: 操作符,但所有要做的就是向下钻取命名空间树;在这样的事情中间不可能有方法。