2008-09-24 42 views
42

Có thể kết nối các phương thức tĩnh với nhau bằng một lớp tĩnh không? Nói rằng tôi muốn làm một việc như sau:Chaining phương pháp tĩnh trong PHP?

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

. . . và rõ ràng là tôi muốn giá trị $ được gán cho số 14. Điều này có thể xảy ra không?

Cập nhật: Nó không làm việc (! Bạn không thể trở về "ngã" - nó không phải là một ví dụ), nhưng đây là nơi suy nghĩ của tôi đã đưa tôi:

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

Sau khi làm việc đó ra, tôi nghĩ rằng nó sẽ chỉ có ý nghĩa hơn để chỉ đơn giản là làm việc với một thể hiện lớp hơn là cố gắng để chuỗi các cuộc gọi chức năng tĩnh (mà không nhìn có thể, trừ khi ví dụ trên có thể được tinh chỉnh bằng cách nào đó).

Trả lời

41

Tôi thích giải pháp được cung cấp bởi Camilo ở trên, về cơ bản vì tất cả những gì bạn đang làm là thay đổi giá trị của thành viên tĩnh và vì bạn muốn chuỗi (mặc dù nó chỉ là đường cú pháp), sau đó instantiating TestClass có lẽ là cách tốt nhất để đi.

tôi muốn đề nghị một mô hình Singleton nếu bạn muốn hạn chế instantiation của lớp:

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

Chỉ cần thực hiện xong phương pháp này và nó hoạt động hoàn hảo! – Wilco

+0

'kết quả chức năng công khai() { trả về $ this :: $ value; } 'là dòng này có nghĩa là ' kết quả chức năng công khai() { trả về $ this :: $ currentValue; } '???? – Val

+0

Thao tác này sẽ không hoạt động ngay khi bạn muốn sử dụng nhiều thẻ cùng nhau. '$ a = TestClass :: getInstance() -> toValue (3) -> add (5);' '$ b = TestClass :: getInstance() -> toValue (7) -> add ($ a-> result()); ' ' echo $ b-> result(); ' Bạn sẽ nhận được 14 thay vì 15. Không xử lý tiền với toán đó. –

1

Tóm lại ... không. :) Toán tử độ phân giải (: :) sẽ làm việc cho phần TetsClass :: toValue (5), nhưng mọi thứ sau đó sẽ chỉ đưa ra một lỗi cú pháp.

Khi không gian tên được triển khai trong 5.3, bạn có thể có "chuỗi" :: toán tử, nhưng tất cả những gì sẽ làm là đi sâu vào cây không gian tên; nó sẽ không thể có phương pháp ở giữa những thứ như thế này.

1

Không, thao tác này sẽ không hoạt động. Toán tử :: cần đánh giá trở lại một lớp, vì vậy sau khi đánh giá TestClass::toValue(5), phương pháp ::add(3) sẽ chỉ có thể đánh giá câu trả lời của câu hỏi cuối cùng.

Vì vậy, nếu toValue(5) trả về số nguyên 5, về cơ bản bạn sẽ gọi số int(5)::add(3) rõ ràng là lỗi.

9

Nếu toValue (x) trả về một đối tượng, bạn có thể làm như thế này:

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

Cung cấp mà toValue trả về một thể hiện mới của các đối tượng, và mỗi phương pháp tiếp theo đột biến nó, trở về một thể hiện của $ này .

+1

Đây không phải là tĩnh mặc dù. – 472084

3

Bạn luôn có thể sử dụng phương pháp đầu tiên như một tĩnh và số còn lại như các phương pháp dụ:

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

Hoặc tốt hơ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); 
    } 
} 

Chỉ cần một FYI .. tôi viết này ra khỏi đỉnh của tôi đầu (ngay tại đây trên trang web). Vì vậy, nó có thể không chạy, nhưng đó là ý tưởng. Tôi có thể cũng đã thực hiện một cuộc gọi phương thức đệ quy để eval, nhưng tôi nghĩ rằng điều này có thể đơn giản hơn. Vui lòng cho tôi biết nếu bạn muốn tôi xây dựng hoặc cung cấp bất kỳ trợ giúp nào khác.

29

Mã nhỏ trên php5.3 ... chỉ để giải trí.

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

Holy crap! Mắt tôi chảy máu! : D –

+4

Điều này có lẽ là phần hay nhất của PHP mà tôi từng thấy. – kaiser

+0

Tôi lồng mã Troll này –

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

Điều này đã lưu ass của tôi :) – DerDu

+2

Đây là câu trả lời đúng! – Maykonn

+0

Đây là giải pháp tuyệt vời mặc dù :) –

1

Điều tốt nhất mà có thể được thực hiện

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

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

Đây là chính xác hơn, dễ dàng hơn, và đọc thân thiện (cho phép mã hoàn thành)

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

Ví dụ:

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

kết quả: 0,63

6

Với php7 bạn sẽ có thể sử dụng cú pháp như mong muốn vì mới 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

Cách nhất dễ nhất tôi đã từng tìm thấy cho phương thức chaining từ sơ thẩm mới hoặc phương thức tĩnh của lớp như sau. Tôi đã sử dụng Late Static Binding ở đây và tôi thực sự yêu thích giải pháp này.

Tôi đã tạo một tiện ích để gửi nhiều thông báo người dùng trên trang tiếp theo bằng cách sử dụng tostr trong 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); 
    } 
} 

Điều này sẽ hoạt động như sau.

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

    ->setOption('showDuration', 5000) 

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

    ->error("Error Message"); 
0

Sử dụng PHP 7! Nếu nhà cung cấp web của bạn không thể -> thay đổi nhà cung cấp! Đừng khóa trong quá khứ.

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

Và rất đơn giản sử dụng:

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

Return (hoặc ném lỗi):

B-A - BA That all. 

hoàn thành hợp đồng.

Quy tắc một: hầu hết được phát triển và duy trì luôn tốt hơn.

Các vấn đề liên quan