usar - self php
¿Encadenando métodos estáticos en PHP? (12)
¡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 uso muy simple:
if( sAB::B()::SEP()::A()::SEP('' - '')::B()::A()::SEP('' '')::success() )
{
echo "That all./n";
}
Retorno (o error de tiro):
B-A - BA That all.
contrato completado
Regla uno: la mayoría evolucionada y mantenible es siempre mejor.
¿Es posible encadenar métodos estáticos juntos usando una clase estática? Digamos que quería hacer algo como esto:
$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 devolver el "yo", ¡no es una instancia!), 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 resolver eso, 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).
Con php7 podrá usar la sintaxis deseada debido a la nueva sintaxis de variables uniformes
<?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;
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 operadores "encadenados", pero todo lo que hará es profundizar en el árbol del espacio de nombres; no será posible tener métodos en medio de cosas como esta.
Esto es más preciso, fácil y fácil de leer (permite completar el código)
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
La forma más sencilla que he encontrado para el encadenamiento de métodos desde la nueva Instancia o método estático de clase es la 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");
Me gusta la solución proporcionada por Camilo más arriba, 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), crear TestClass probablemente sea la mejor manera de hacerlo. .
Sugeriría un patrón Singleton si quieres restringir la creación de instancias 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();
No, esto no funcionará El operador ::
necesita evaluar de nuevo a una clase, por lo que después de la TestClass::toValue(5)
, el método ::add(3)
solo podría evaluar la respuesta de la última.
Entonces, si toValue(5)
devuelve el entero 5, básicamente toValue(5)
llamando a int(5)::add(3)
que obviamente es un error.
Pequeño código loco 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();
Si toValue (x) devuelve un objeto, podría hacer esto:
$value = TestClass::toValue(5)->add(3)->substract(2)->add(8);
Siempre que toValue devuelva una nueva instancia del objeto, y cada método siguiente lo muta, devolviendo una instancia de $ this.
Siempre puedes usar el método First como método estático 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);
}
}
Solo un FYI ... Escribí esto en 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.
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();
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();