Цепные статические методы в PHP? - PullRequest
48 голосов
/ 24 сентября 2008

Возможно ли связать статические методы вместе, используя статический класс? Скажем, я хотел сделать что-то вроде этого:

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

После этого я думаю, что было бы более разумно просто работать с экземпляром класса, а не пытаться связывать статические вызовы функций (что не представляется возможным, если приведенный выше пример не может быть каким-то образом изменен).

Ответы [ 14 ]

46 голосов
/ 24 сентября 2008

Мне нравится решение, предоставленное Camilo выше, по сути, поскольку все, что вы делаете, это изменение значения статического члена, и так как вы действительно хотите создать цепочку (даже если это только синтетический сахар), то создание TestClass, вероятно, является лучшим путь.

Я бы предложил шаблон Singleton, если вы хотите ограничить создание экземпляров класса:

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();
40 голосов
/ 10 августа 2012
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();
31 голосов
/ 05 июля 2012

Маленький сумасшедший код на 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();
10 голосов
/ 02 сентября 2015

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

Демо

9 голосов
/ 24 сентября 2008

Если toValue (x) возвращает объект, вы можете сделать так:

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

При условии, что toValue возвращает новый экземпляр объекта, а каждый следующий метод изменяет его, возвращая экземпляр $ this.

3 голосов
/ 24 сентября 2008

Вы всегда можете использовать метод 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, но я подумал, что это может быть проще. Пожалуйста, дайте мне знать, если вы хотите, чтобы я уточнил или предоставил любую другую помощь.

2 голосов
/ 21 октября 2018

Технически вы можете вызывать статический метод для экземпляра, такого как $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);

Выходы int(14).

Это примерно то же самое, что и возвращение __CLASS__, которое использовалось в другом ответе . Я скорее надеюсь, что никто никогда не решит использовать эти формы API, но вы просили об этом.

1 голос
/ 02 сентября 2014

Это более точно, просто и удобно для чтения (допускает завершение кода)

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

1 голос
/ 20 августа 2013

Лучшее, что можно сделать

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

$_t='S';
${${S::X()}::F()}::C();
1 голос
/ 24 сентября 2008

В двух словах ... нет. :) Оператор разрешения (: :) будет работать для части TetsClass :: toValue (5), но все, что после этого просто выдаст синтаксическую ошибку.

После того, как пространства имен реализованы в 5.3, вы можете иметь «цепочечные» операторы ::, но все, что вам нужно будет сделать, это развернуть дерево имен; не будет возможности иметь методы в середине подобных вещей.

...