programing

PHP에서 정적 메서드를 연결하시겠습니까?

powerit 2023. 9. 5. 20:48
반응형

PHP에서 정적 메서드를 연결하시겠습니까?

정적 클래스를 사용하여 정적 메서드를 체인으로 연결할 수 있습니까?다음과 같은 일을 하고 싶다고 말합니다.

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

이 문제를 해결한 후에는 정적 함수 호출을 체인으로 연결하려고 하기보다는 클래스 인스턴스로 간단히 작업하는 것이 더 이치에 맞을 것 같습니다(위의 예를 어떻게든 수정할 수 없다면 불가능해 보입니다).

위의 Camilo가 제공한 솔루션이 마음에 듭니다. 기본적으로 정적 멤버의 값을 변경하는 것뿐이고, 체인(합성 설탕일 뿐이지만)을 원하기 때문에 TestClass를 인스턴스화하는 것이 가장 좋은 방법일 것입니다.

클래스의 인스턴스화를 제한하려면 싱글턴 패턴을 제안합니다.

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

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

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;

데모

ToValue(x)가 객체를 반환하는 경우 다음과 같이 할 수 있습니다.

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

이를 값에 제공하면 개체의 새 인스턴스가 반환되고 각 다음 메서드가 이를 변형하여 $this 인스턴스가 반환됩니다.

이것은 더 정확하고, 쉽고, 읽기 쉬운 방법입니다(코드 완성 가능).

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

사람들은 미친 듯이 이것을 너무 복잡하게 만들고 있습니다.

다음을 확인하십시오.

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

항상 첫 번째 방법을 정적 방법으로 사용하고 나머지 방법을 인스턴스 방법으로 사용할 수 있습니다.

$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로 할 수도 있었지만, 이것이 더 단순할 수도 있다고 생각했습니다.제가 더 자세히 설명하거나 다른 도움이 필요하시면 말씀해주세요.

기술적으로 다음과 같은 인스턴스에서 정적 메서드를 호출할 수 있습니다.$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를 실제로 사용하기로 결정하지 않기를 바라지만, 당신은 그것을 요청했습니다.

간단히 말해서...no. :) TetsClass:: toValue(5) 부분에 대해 해상도 연산자(::)가 작동하지만, 그 이후의 모든 작업은 구문 오류만 발생시킵니다.

5.3에서 네임스페이스가 구현되면 "체인" :: 연산자를 사용할 수 있지만 네임스페이스 트리를 통해 드릴다운하는 것만으로는 이러한 중간에 메서드를 사용할 수 없습니다.

할 수 있는 최선을 다합니다.

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

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

안 돼요, 안 돼요::연산자는 클래스에 대해 다시 평가해야 합니다, 그래서 그 후에.TestClass::toValue(5) 가평, 가평,::add(3)방법은 마지막 하나의 답에 대해서만 평가할 수 있습니다.

그래서 만약에toValue(5)정수 5를 반환했습니다. 기본적으로 호출하는 것입니다.int(5)::add(3)그것은 명백히 오류입니다.

클래스의 새 인스턴스 또는 정적 메서드에서 메서드 체인을 찾는 가장 쉬운 방법은 다음과 같습니다.저는 여기서 Late Static Binding을 사용했고 이 솔루션을 정말 좋아했습니다.

다음 페이지에 tstrin 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


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

다른 방법을 사용할 수 있습니다.getInstance 7 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

다음과 같은 역할도 합니다.

ExampleClass::withBanners()->withoutTranslations()->collection($values)

용사를 합니다.new static(self::class);

public static function withoutTranslations(): self
{
    self::$withoutTranslations = true;
    
    return new static(self::class);
}

public static function withBanners(): self
{
    return new static(self::class);
}

public static function collection(values): self
{
    return $values;
}

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)

완성된 계약

규칙 1: 가장 진화하고 유지할 수 있는 것이 항상 더 좋습니다.

언급URL : https://stackoverflow.com/questions/125268/chaining-static-methods-in-php

반응형