2008-09-24 28 views
42

¿Es posible encadenar métodos estáticos juntos usando una clase estática? Digamos que quería hacer algo como esto:Encadenamiento de métodos estáticos en PHP?

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

. . . y obviamente me gustaría que $ value se le asigne el número 14. ¿Es esto posible?

actualización: No funciona (! No se puede volver "auto" - no es un ejemplo), pero aquí es donde mis pensamientos me han llevado:

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

Después de trabajar que fuera, creo que tendría más sentido simplemente trabajar con una instancia de clase en lugar de tratar de encadenar llamadas a funciones estáticas (lo que no parece posible, a menos que el ejemplo anterior pueda modificarse de alguna manera).

Respuesta

41

Me gusta la solución proporcionada por Camilo anteriormente, básicamente porque lo único que estás haciendo es alterar el valor de un miembro estático, y como quieres encadenar (aunque solo sea azúcar sintáctica), la instancia de TestClass es probablemente la la mejor manera de ir

me gustaría sugerir un patrón Singleton si desea restringir la instanciación de la clase:

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

¡Acaba de implementar este método y funciona perfectamente! – Wilco

+0

'public function result() { return $ this :: $ value; } 'es esta línea destinada a ser ' public function result() { return $ this :: $ currentValue; } '???? – Val

+0

Esto no funcionará tan pronto como desee usar más de uno. '$ a = TestClass :: getInstance() -> toValue (3) -> add (5);' '$ b = TestClass :: getInstance() -> toValue (7) -> add ($ a-> result()); ' ' echo $ b-> result(); ' Obtendrá 14 en lugar de 15. No maneje el dinero con esa matemática. –

1

En pocas palabras ... no. :) El operador de resolución (: :) funcionaría para la parte TetsClass :: toValue (5), pero todo lo demás solo dará un error de sintaxis.

Una vez que los espacios de nombres se implementan en 5.3, puede tener los operadores "encadenados" ::, pero todo lo que se hará es profundizar en el árbol del espacio de nombres; no será posible tener métodos en medio de cosas como esta.

1

No, esto no funcionará. El operador :: necesita evaluar de nuevo a una clase, por lo que después de la evaluación TestClass::toValue(5), el método ::add(3) solo podría evaluar en la respuesta de la última.

Así que si toValue(5) devolviera el número entero 5, básicamente llamaría al int(5)::add(3), lo que obviamente es un error.

9

Si toValue (x) devuelve un objeto, se puede hacer así:

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

Siempre que toValue devuelve una nueva instancia del objeto, y cada método siguiente muta, devolviendo una instancia de $ este .

+1

Aunque no son estáticos. – 472084

3

Siempre se puede utilizar el primer método como estática y el resto como métodos de instancia:

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

O mejor aún:

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

Sólo una intensa .. me escribió esto de la parte superior de mi cabeza (aquí en el sitio). Por lo tanto, puede no funcionar, pero esa es la idea. También podría haber hecho una llamada de método recursivo a eval, pero pensé que esto podría ser más simple. Por favor, avíseme si desea que elabore o proporcione cualquier otra ayuda.

29

Little crazy code en php5.3 ... solo por diversión.

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

¡Santa mierda! ¡Mis ojos sangran! : D –

+4

Esta es quizás la mejor pieza de PHP que he visto en mi vida. – kaiser

+0

doo este código Troll –

37
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(); 
+1

Esto me ha salvado el culo :) – DerDu

+2

¡Esta es la respuesta correcta! – Maykonn

+0

Sin embargo, esta es una solución increíble :) –

1

Lo mejor que se puede hacer

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

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

Esto es más preciso, más fácil, y leer mascotas (permite código de finalización)

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

Ejemplo:

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

resultado: 0,63

6

Con php7 usted será capaz de utilizar la sintaxis deseado debido a la nueva Uniform Variable Syntax

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

1

La manera más fácil que he encontrado nunca para El método de encadenamiento de la nueva Instancia o método estático de clase es el siguiente. He utilizado Enlace estático tardío aquí y realmente me encantó esta solución.

He creado una utilidad para enviar múltiples notificaciones de usuario en la página siguiente usando tostr en Laravel.

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

Esto funcionará de la siguiente manera.

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

    ->setOption('showDuration', 5000) 

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

    ->error("Error Message"); 
0

¡Usa PHP 7! Si su proveedor web no puede -> cambiar de proveedor! No te encierres en el pasado.

class sAB 
{ 
    static private $sep = '-';  
    static public function A() 
    { 
    echo 'A'; 
    return __CLASS__; 
    } 
    static public function B() 
    { 
    echo 'B'; 
    return __CLASS__; 
    } 
    static public function SEP() 
    { 
    $argv = func_get_args(); 
    $argc = func_num_args(); 
    if($argc == 1) self::$sep = $argv[0]; 
    echo self::$sep; 
    return __CLASS__; 
    } 
    static public function success() 
    { 
    return self::$sep == ' '; 
    } 
} 

y muy simple uso:

if(sAB::B()::SEP()::A()::SEP(' - ')::B()::A()::SEP(' ')::success()) 
{ 
    echo "That all.\n"; 
} 

Retorno (o tirar de error):

B-A - BA That all. 

contrato terminado.

Regla uno: más evolucionado y mantenible es siempre mejor.