Можно ли связать статические методы вместе с помощью статического класса? Скажем, я хотел сделать что-то вроде этого:
$value = TestClass::toValue(5)::add(3)::subtract(2)::add(8)::result();
. . . и, очевидно, я бы хотел, чтобы $ value было присвоено число 14. Возможно ли это?
Обновлять: Не работает (вы не можете вернуть "self" - это не экземпляр!), Но вот куда меня привели мои мысли:
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;
}
}
После работы над этим, я думаю, было бы разумнее просто работать с экземпляром класса, а не пытаться связывать вызовы статических функций (что не выглядит возможным, если только приведенный выше пример не может быть каким-то образом изменен).






Короче ... нет. :) Оператор разрешения (: :) будет работать для части TetsClass :: toValue (5), но все, что происходит после этого, просто выдаст синтаксическую ошибку.
Как только пространства имен реализованы в версии 5.3, вы можете «связать» операторы ::, но все, что вам нужно сделать, это развернуть дерево пространств имен; невозможно иметь методы посреди таких вещей.
Нет, это не сработает. Оператор :: должен возвращать оценку классу, поэтому после оценки TestClass::toValue(5) метод ::add(3) сможет оценить только ответ последнего.
Итак, если toValue(5) вернет целое число 5, вы в основном вызовете int(5)::add(3), что, очевидно, является ошибкой.
Если toValue (x) возвращает объект, вы можете сделать следующее:
$value = TestClass::toValue(5)->add(3)->substract(2)->add(8);
При условии, что toValue возвращает новый экземпляр объекта, и каждый следующий метод изменяет его, возвращая экземпляр $ this.
Мне нравится решение, предоставленное 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();
Это не сработает, если вы захотите использовать более одного вместе. $a = TestClass::getInstance()->toValue(3)->add(5);$b = TestClass::getInstance()->toValue(7)->add($a->result());echo $b->result(); Вы получите 14 вместо 15. Не обращайтесь с деньгами с этой математикой.
Определение конструктора private __construct () { } должно быть private function __construct () { }. Кроме того, return $this::$currentValue; должен быть return self::$currentValue;.
Я также обнаружил, что это не цепочка переданного одного метода. Также это не сработает, если вы используете ключевое слово final в своем классе.
Вы всегда можете использовать метод 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 рекурсивным методом, но я подумал, что это может быть проще. Пожалуйста, дайте мне знать, если вы хотите, чтобы я уточнил или предоставил любую другую помощь.
Маленький сумасшедший код на 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();
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();
Я думаю, что когда дело касается синтаксиса (а не лучших практик программирования), это лучший ответ на этот вопрос.
В этом ответе отсутствует образовательное объяснение.
Лучшее, что можно сделать
class S
{
public static function __callStatic($name,$args)
{
echo 'called S::'.$name . '( )<p>';
return '_t';
}
}
$_t='S';
${${S::X()}::F()}::C();
это путь назад php5.4?
Это более точный, простой и удобный для чтения (позволяет автозавершение кода)
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
С 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;
Самый простой способ, который я когда-либо находил для связывания методов из нового экземпляра или статического метода класса, приведен ниже. Я использовал здесь Late Static Binding, и мне очень понравилось это решение.
Я создал утилиту для отправки нескольких уведомлений пользователей на следующей странице с помощью tostr в 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);
}
}
Это будет работать, как показано ниже.
Toaster::success("Success Message", "Success Title")
->setOption('showDuration', 5000)
->warning("Warning Message", "Warning Title")
->error("Error Message");
Используйте PHP 7! Если ваш провайдер не может -> смените провайдера! Не зацикливайтесь на прошлом.
final 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();
var_dump($value);
Возврат (или выдача ошибки):
int(14)
завершенный договор.
Правило первое: самое развитое и удобное в обслуживании всегда лучше.
Технически вы можете вызвать статический метод для такого экземпляра, как $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, но вы просили об этом.
Полнофункциональный пример объединения методов со статическими атрибутами:
<?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);
}
}
Пример использования:
Response::getInstance()->code(400)->sendError("Lacks id in request");
Люди слишком усложняют это, как сумасшедшие.
Проверь это:
class OopClass
{
public $first;
public $second;
public $third;
public static function make($first)
{
return new OopClass($first);
}
public function __construct($first)
{
$this->first = $first;
}
public function second($second)
{
$this->second = $second;
return $this;
}
public function third($third)
{
$this->third = $third;
return $this;
}
}
Использование:
OopClass::make('Hello')->second('To')->third('World');
Вот еще один способ без использования метода getInstance (протестирован на PHP 7.x):
class TestClass
{
private $result = 0;
public function __call($method, $args)
{
return $this->call($method, $args);
}
public static function __callStatic($method, $args)
{
return (new static())->call($method, $args);
}
private function call($method, $args)
{
if (! method_exists($this , '_' . $method)) {
throw new Exception('Call undefined method ' . $method);
}
return $this->{'_' . $method}(...$args);
}
private function _add($num)
{
$this->result += $num;
return $this;
}
private function _subtract($num)
{
$this->result -= $num;
return $this;
}
public function result()
{
return $this->result;
}
}
Класс можно использовать следующим образом:
$res1 = TestClass::add(5)
->add(3)
->subtract(2)
->add(8)
->result();
echo $res1 . PHP_EOL; // 14
$res2 = TestClass::subtract(1)->add(10)->result();
echo $res2 . PHP_EOL; // 9
public function result() { return $this::$value; }эта линия должна бытьpublic function result() { return $this::$currentValue; }????