it-swarm.com.de

Verkettung statischer Methoden in PHP?

Ist es möglich, statische Methoden mithilfe einer statischen Klasse zu verketten? Sagen wir, ich wollte so etwas machen:

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

. . . und natürlich möchte ich, dass $ value die Nummer 14 bekommt. Ist das möglich?

Update : Es funktioniert nicht (Sie können "self" nicht zurückgeben - es ist keine Instanz!), Aber dies ist, wohin mich meine Gedanken geführt haben:

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

Nachdem ich das herausgefunden habe, ist es meiner Meinung nach sinnvoller, einfach mit einer Klasseninstanz zu arbeiten, als zu versuchen, statische Funktionsaufrufe zu verketten (was nicht möglich erscheint, es sei denn, das obige Beispiel könnte irgendwie optimiert werden).

46
Wilco

Ich mag die von Camilo bereitgestellte Lösung, im Wesentlichen, da Sie lediglich den Wert eines statischen Members ändern und da Sie Verketten möchten (auch wenn es nur synthetischer Zucker ist), dann ist die Instantiierung von TestClass wahrscheinlich der beste Weg .

Ich würde ein Singleton-Muster vorschlagen, wenn Sie die Instantiierung der Klasse einschränken möchten:

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();
44
Mathew Byrne
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();
39
Ariful Islam

Ein bisschen verrückter Code auf PHP5.3 ... nur zum Spaß.

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

Wenn toValue (x) ein Objekt zurückgibt, können Sie Folgendes tun:

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

Wenn toValue angegeben wird, wird eine neue Instanz des Objekts zurückgegeben, und jede nächste Methode mutiert es, wobei eine Instanz von $ this zurückgegeben wird.

9

Mit php7 können Sie die gewünschte Syntax aufgrund der neuen Uniform Variable Syntax verwenden.

<?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

7
sectus

Sie können die First-Methode immer als statische und die verbleibenden als Instanzmethoden verwenden:

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

Oder noch besser:

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

Nur eine FYI .. Ich habe dies aus meinem Kopf geschrieben (direkt hier auf der Website). Es kann also nicht laufen, aber das ist die Idee. Ich hätte auch eine rekursive Methode aufrufen können, aber ich dachte, das könnte einfacher sein. Bitte lassen Sie mich wissen, ob Sie weitere Hilfe benötigen oder andere Hilfe leisten möchten.

3
Phobis

Das Beste, was getan werden kann

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

$_t='S';
${${S::X()}::F()}::C();
1
jsdeveloper

Technisch können Sie eine statische Methode für eine Instanz wie $object::method() in PHP 7+ aufrufen. Die Rückgabe einer neuen Instanz sollte als Ersatz für return self dienen. Und es funktioniert tatsächlich.

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

Ausgänge int(14)

Dies entspricht etwa der Rückgabe von __CLASS__ als in anderer Antwort . Ich hoffe eher, dass sich niemand dafür entscheidet, diese API-Formen tatsächlich zu verwenden, aber Sie haben danach gefragt.

1
sanmai

Dies ist genauer, einfacher und lesefreundlicher (ermöglicht Code-Vervollständigung)

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

Beispiel:

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

Ergebnis: 0.63

Kurz gesagt ... nein. :) Der Auflösungsoperator (: :) würde für den Teil TetsClass :: toValue (5) funktionieren, aber danach wird nur ein Syntaxfehler ausgegeben.

Sobald Namespaces in 5.3 implementiert wurden, können Sie :: Operatoren "verketten", aber alles, was Sie tun müssen, ist ein Drilldown durch die Namespace-Struktur. Es ist nicht möglich, mitten in solchen Dingen Methoden zu haben.

1
dirtside

Der einfachste Weg, den ich je für die Methodenverkettung aus der neuen Instanz- oder statischen Methode der Klasse gefunden habe, ist wie folgt. Ich habe hier Late Static Binding verwendet und diese Lösung hat mir sehr gut gefallen.

Ich habe ein Dienstprogramm zum Senden mehrerer Benutzerbenachrichtigungen auf der nächsten Seite mit tostr in Laravel erstellt.

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

Dies funktioniert wie folgt.

Toaster::success("Success Message", "Success Title")

    ->setOption('showDuration', 5000)

    ->warning("Warning Message", "Warning Title")

    ->error("Error Message");
0
Pratik Soni

Nein, das geht nicht. Der ::-Operator muss eine Auswertung für eine Klasse durchführen, sodass nach der Auswertung von TestClass::toValue(5) die ::add(3)-Methode nur die Antwort der letzten bewerten kann.

Wenn also toValue(5) die ganze Zahl 5 zurückgegeben hat, würden Sie im Grunde int(5)::add(3) aufrufen, was offensichtlich ein Fehler ist.

0
jW.

Voll funktionsfähiges Beispiel für die Verkettung von Methoden mit statischen Attributen:

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

Anwendungsbeispiel:

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