【问题标题】:Chaining Static Methods in PHP?在 PHP 中链接静态方法?
【发布时间】:2010-09-12 14:54:35
【问题描述】:

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

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

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

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

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;
    }
}

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

【问题讨论】:

    标签: php oop method-chaining


    【解决方案1】:

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

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

    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();
    

    【讨论】:

    • public function result() { return $this::$value; } 这行是public function result() { return $this::$currentValue; } ????
    • 当您想同时使用多个时,这将不起作用。 $a = TestClass::getInstance()->toValue(3)->add(5); $b = TestClass::getInstance()->toValue(7)->add($a->result()); echo $b->result(); 你会得到 14 而不是 15。不要用数学来处理金钱。
    • 构造函数定义private __construct () { }应该是private function __construct () { }。另外,return $this::$currentValue; 应该是 return self::$currentValue;
    • 我还发现这并没有链式传递一个方法。如果您在课堂上使用关键字final,这也不起作用。
    【解决方案2】:
    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();
    

    【讨论】:

    • 我认为,当谈到语法(不是最佳编码实践)时,这是这个问题的最佳答案。
    • 这个答案缺少教育解释。
    • 对性能有影响吗?
    【解决方案3】:

    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();
    

    【讨论】:

      【解决方案4】:

      有了新的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

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

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

          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;
              }
          }
          

          示例:

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

          结果:0.63

          【讨论】:

            【解决方案7】:

            人们疯狂地把这件事复杂化了。

            看看这个:

            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;
                }
            }
            

            用法:

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

            【讨论】:

              【解决方案8】:

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

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

              或者更好:

               $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);
                   }
               }
              

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

              【讨论】:

                【解决方案9】:

                从技术上讲,您可以在 PHP 7+ 中的 $object::method() 之类的实例上调用静态方法,因此返回一个新实例应该可以替代 return selfAnd indeed it works.

                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);
                

                输出int(14)

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

                【讨论】:

                  【解决方案10】:

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

                  一旦在 5.3 中实现了命名空间,您就可以使用“链式”:: 运算符,但所做的只是向下钻取命名空间树;在这样的事情中间不可能有方法。

                  【讨论】:

                    【解决方案11】:

                    可以做到的最好的

                    class S
                    {
                        public static function  __callStatic($name,$args)
                        {
                            echo 'called S::'.$name . '( )<p>';
                            return '_t';
                        }
                    }
                    
                    $_t='S';
                    ${${S::X()}::F()}::C();
                    

                    【讨论】:

                    • 这是 php5.4 的回归?
                    【解决方案12】:

                    不,这行不通。 :: 操作符需要计算回一个类,所以在 TestClass::toValue(5) 计算之后,::add(3) 方法只能对最后一个的答案进行计算。

                    因此,如果toValue(5) 返回整数 5,您基本上会调用int(5)::add(3),这显然是一个错误。

                    【讨论】:

                      【解决方案13】:

                      我发现从类的新实例或静态方法链接方法的最简单方法如下。我在这里使用了后期静态绑定,我真的很喜欢这个解决方案。

                      我创建了一个实用程序,用于在 Laravel 中使用 tostr 在下一页发送多个用户通知。

                      <?php
                      
                      namespace App\Utils;
                      
                      use Session;
                      
                      use Illuminate\Support\HtmlString;
                      
                      class Toaster
                      {
                          private static $options = [
                      
                              "closeButton" => false,
                      
                              "debug" => false,
                      
                              "newestOnTop" => false,
                      
                              "progressBar" => false,
                      
                              "positionClass" => "toast-top-right",
                      
                              "preventDuplicates" => false,
                      
                              "onclick" => null,
                      
                              "showDuration" => "3000",
                      
                              "hideDuration" => "1000",
                      
                              "timeOut" => "5000",
                      
                              "extendedTimeOut" => "1000",
                      
                              "showEasing" => "swing",
                      
                              "hideEasing" => "linear",
                      
                              "showMethod" => "fadeIn",
                      
                              "hideMethod" => "fadeOut"
                          ];
                      
                          private static $toastType = "success";
                      
                          private static $instance;
                      
                          private static $title;
                      
                          private static $message;
                      
                          private static $toastTypes = ["success", "info", "warning", "error"];
                      
                          public function __construct($options = [])
                          {
                              self::$options = array_merge(self::$options, $options);
                          }
                      
                          public static function setOptions(array $options = [])
                          {
                              self::$options = array_merge(self::$options, $options);
                      
                              return self::getInstance();
                          }
                      
                          public static function setOption($option, $value)
                          {
                              self::$options[$option] = $value;
                      
                              return self::getInstance();
                          }
                      
                          private static function getInstance()
                          {
                              if(empty(self::$instance) || self::$instance === null)
                              {
                                  self::setInstance();
                              }
                      
                              return self::$instance;
                          }
                      
                          private static function setInstance()
                          {
                              self::$instance = new static();
                          }
                      
                          public static function __callStatic($method, $args)
                          {
                              if(in_array($method, self::$toastTypes))
                              {
                                  self::$toastType = $method;
                      
                                  return self::getInstance()->initToast($method, $args);
                              }
                      
                              throw new \Exception("Ohh my god. That toast doesn't exists.");
                          }
                      
                          public function __call($method, $args)
                          {
                              return self::__callStatic($method, $args);
                          }
                      
                          private function initToast($method, $params=[])
                          {
                              if(count($params)==2)
                              {
                                  self::$title = $params[0];
                      
                                  self::$message = $params[1];
                              }
                              elseif(count($params)==1)
                              {
                                  self::$title = ucfirst($method);
                      
                                  self::$message = $params[0];
                              }
                      
                              $toasters = [];
                      
                              if(Session::has('toasters'))
                              {
                                  $toasters = Session::get('toasters');
                              }
                      
                              $toast = [
                      
                                  "options" => self::$options,
                      
                                  "type" => self::$toastType,
                      
                                  "title" => self::$title,
                      
                                  "message" => self::$message
                              ];
                      
                              $toasters[] = $toast;
                      
                              Session::forget('toasters');
                      
                              Session::put('toasters', $toasters);
                      
                              return $this;
                          }
                      
                          public static function renderToasters()
                          {
                              $toasters = Session::get('toasters');
                      
                              $string = '';
                      
                              if(!empty($toasters))
                              {
                                  $string .= '<script type="application/javascript">';
                      
                                  $string .= "$(function() {\n";
                      
                                  foreach ($toasters as $toast)
                                  {
                                      $string .= "\n toastr.options = " . json_encode($toast['options'], JSON_PRETTY_PRINT) . ";";
                      
                                      $string .= "\n toastr['{$toast['type']}']('{$toast['message']}', '{$toast['title']}');";
                                  }
                      
                                  $string .= "\n});";
                      
                                  $string .= '</script>';
                              }
                      
                              Session::forget('toasters');
                      
                              return new HtmlString($string);
                          }
                      }
                      

                      这将如下所示。

                      Toaster::success("Success Message", "Success Title")
                      
                          ->setOption('showDuration', 5000)
                      
                          ->warning("Warning Message", "Warning Title")
                      
                          ->error("Error Message");
                      

                      【讨论】:

                        【解决方案14】:

                        具有静态属性的方法链接的完整功能示例:

                        <?php
                        
                        
                        class Response
                        {
                            static protected $headers = [];
                            static protected $http_code = 200;
                            static protected $http_code_msg = '';
                            static protected $instance = NULL;
                        
                        
                            protected function __construct() { }
                        
                            static function getInstance(){
                                if(static::$instance == NULL){
                                    static::$instance = new static();
                                }
                                return static::$instance;
                            }
                        
                            public function addHeaders(array $headers)
                            {
                                static::$headers = $headers;
                                return static::getInstance();
                            }
                        
                            public function addHeader(string $header)
                            {
                                static::$headers[] = $header;
                                return static::getInstance();
                            }
                        
                            public function code(int $http_code, string $msg = NULL)
                            {
                                static::$http_code_msg = $msg;
                                static::$http_code = $http_code;
                                return static::getInstance();
                            }
                        
                            public function send($data, int $http_code = NULL){
                                $http_code = $http_code != NULL ? $http_code : static::$http_code;
                        
                                if ($http_code != NULL)
                                    header(trim("HTTP/1.0 ".$http_code.' '.static::$http_code_msg));
                        
                                if (is_array($data) || is_object($data))
                                    $data = json_encode($data);
                        
                                echo $data; 
                                exit();     
                            }
                        
                            function sendError(string $msg_error, int $http_code = null){
                                $this->send(['error' => $msg_error], $http_code);
                            }
                        }
                        

                        使用示例:

                        Response::getInstance()->code(400)->sendError("Lacks id in request");
                        

                        【讨论】:

                          【解决方案15】:

                          这是另一种不通过 getInstance 方法的方法(在 PHP 7.x 上测试):

                          class TestClass
                          {
                              private $result = 0;
                          
                              public function __call($method, $args)
                              {
                                  return $this->call($method, $args);
                              }
                          
                              public static function __callStatic($method, $args)
                              {
                                  return (new static())->call($method, $args);
                              }
                          
                              private function call($method, $args)
                              {
                                  if (! method_exists($this , '_' . $method)) {
                                      throw new Exception('Call undefined method ' . $method);
                                  }
                          
                                  return $this->{'_' . $method}(...$args);
                              }
                          
                              private function _add($num)
                              {
                                  $this->result += $num;
                          
                                  return $this;
                              }
                          
                              private function _subtract($num)
                              {
                                  $this->result -= $num;
                          
                                  return $this;
                              }
                          
                              public function result()
                              {
                                  return $this->result;
                              }
                          }
                          

                          该类可以如下使用:

                          $res1 = TestClass::add(5)
                              ->add(3)
                              ->subtract(2)
                              ->add(8)
                              ->result();
                          
                          echo $res1 . PHP_EOL; // 14
                          
                          $res2 = TestClass::subtract(1)->add(10)->result();
                          echo $res2 . PHP_EOL; // 9
                          

                          【讨论】:

                            【解决方案16】:

                            使用 PHP 7!如果您的网络提供商不能 --> 更改提供商!不要锁定过去。

                            final 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;
                                }
                            }
                            

                            And very simple use:

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

                            返回(或抛出错误):

                            int(14)
                            

                            已完成合同。

                            规则一:最进化和可维护的总是更好。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2010-09-12
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2011-07-09
                              • 2012-03-01
                              相关资源
                              最近更新 更多