在PHP中链接静态方法?
是否有可能使用静态类链接静态方法? 说我想做这样的事情:
$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();
。 。 。 显然我会希望给$ value赋予数字14.这可能吗?
更新 :它不起作用(你不能返回“自我” – 这不是一个实例!),但这是我的想法所采取的:
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; } }
在解决这个问题之后,我认为仅仅使用一个类实例就可以了,而不是试图链接静态函数调用(除非上面的例子可以被调整,否则看起来不可能)。
我喜欢上面的Camilo提供的解决scheme,基本上,因为你所做的只是改变静态成员的价值,而且因为你需要链接(即使它只是syntically糖),所以实例化TestClass可能是最好的方法。
如果你想限制类的实例化,我会build议一个单例模式:
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();
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();
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();
如果toValue(x)返回一个对象,你可以这样做:
$value = TestClass::toValue(5)->add(3)->substract(2)->add(8);
假设toValue返回对象的一个新实例,并且每个下一个方法改变它,返回一个$ this的实例。
您始终可以将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); } }
只是一个FYI ..我写了我的头顶(在这里的网站)。 所以,它可能不会运行,但这是这个想法。 我也可以做一个recursion的方法调用eval,但我认为这可能会更简单。 请让我知道如果你想我详细说明或提供任何其他帮助。
使用php7,您将能够使用所需的语法,因为新的统一variables语法
<?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;
演示
简而言之,不, :)parsing运算符(:)会适用于TetsClass :: toValue(5)部分,但之后的所有内容只会给出语法错误。
一旦命名空间在5.3中实现,您可以拥有“chained”::运算符,但是只要在名称空间树中向下钻取即可; 在这样的事情中间不可能有方法。
最好的,可以做到的
class S { public static function __callStatic($name,$args) { echo 'called S::'.$name . '( )<p>'; return '_t'; } } $_t='S'; ${${S::X()}::F()}::C();
这是更准确,更容易,更容易阅读(允许代码完成)
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
不,这不行。 ::
运算符需要返回一个类,所以在TestClass::toValue(5)
计算之后, ::add(3)
方法只能评估最后一个的答案。
所以如果toValue(5)
返回整数5,你基本上会调用int(5)::add(3)
,这显然是一个错误。
从新的实例或类的静态方法中find的方法链最简单的方法如下。 我在这里使用了Late Static Binding,我非常喜欢这个解决scheme。
我创build了一个实用程序,使用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");