2011-08-15 43 views
60
class MyClass { 
    var $lambda; 
    function __construct() { 
    $this->lambda = function() {echo 'hello world';}; 
    // no errors here, so I assume that this is legal 
    } 
} 

$myInstance = new MyClass(); 
$myInstance->lambda(); 
//Fatal error: Call to undefined method MyClass::lambda() 

Vậy cú pháp chính xác để đạt các biến lớp là gì?Làm thế nào để gọi một đóng cửa là một biến lớp?

Trả lời

158

Trong PHP, các phương thức và thuộc tính nằm trong một không gian tên riêng biệt (bạn có thể có một phương thức và thuộc tính có cùng tên) và liệu bạn có đang truy cập thuộc tính hay phương pháp hay không. .

$expr->something() là cuộc gọi phương thức, do đó, PHP sẽ tìm kiếm something trong danh sách phương pháp của lớp học.

$expr->something là tìm nạp thuộc tính, do đó, PHP sẽ tìm kiếm something trong danh sách thuộc tính của lớp học.

$myInstance->lambda(); được phân tách như một lời gọi phương thức, do đó PHP tìm kiếm một phương thức có tên lambda trong lớp học của bạn, nhưng không có phương pháp như vậy (vì thế Gọi phương pháp xác định lỗi).

Vì vậy, bạn phải sử dụng cú pháp tìm nạp thuộc tính để tìm nạp lambda và sau đó gọi hàm đó.

  • Kể từ PHP 7.0, bạn có thể làm điều này với ($obj->lambda)():

    ($obj->lambda)(); 
    

    Dấu ngoặc chắc chắn rằng PHP phân tích ($obj->lambda) như lấy tài sản có tên lambda. Sau đó, () gọi kết quả tìm nạp thuộc tính.

  • hoặc bạn có thể làm điều này với ->lambda->__invoke():

    $myInstance = new MyClass(); 
    $myInstance->lambda->__invoke(); 
    

    __invoke là một trong những PHP's magic methods. Khi một đối tượng thực hiện phương thức này, nó sẽ trở thành không thể gọi được: nó có thể được gọi bằng cách sử dụng cú pháp $var(). Các hàm ẩn danh là các cá thể của Closure, thực hiện __invoke.

  • Hoặc gán nó vào một biến cục bộ:

    $lambda = $myInstance->lambda; 
    $lambda(); 
    
  • Hoặc gọi nó bằng cách sử call_user_func:

    call_user_func($myInstance->lambda); 
    

    call_user_func thể gọi bất kỳ callable, bao gồm các chức năng ẩn danh.

  • Ngoài ra, nếu đây là một mô hình phổ biến trong mã của bạn, bạn có thể thiết lập một phương pháp __call để chuyển tiếp cuộc gọi đến lambda của bạn:

    class MyClass 
    { 
        private $lambda; 
    
        public function __construct() 
        { 
         $this->lambda = function() { 
          echo "Hello world!\n"; 
         }; 
        } 
    
        public function __call($name, $args) 
        { 
         return call_user_func_array($this->$name, $args); 
        } 
    } 
    

    Bây giờ công trình này:

    $myInstance = new MyClass(); 
    $myInstance->lambda(); 
    

    Kể từ PHP 5.4 bạn thậm chí có thể làm điều đó trong một đặc điểm:

    trait LambdasAsMethods 
    { 
        public function __call($name, $args) 
        { 
         return call_user_func_array($this->$name, $args); 
        } 
    } 
    
    class MyClass 
    { 
        use LambdasAsMethods; 
    
        private $lambda; 
    
        public function __construct() 
        { 
         $this->lambda = function() { 
          echo "Hello World!\n"; 
         }; 
        } 
    } 
    
    $myInstance = new MyClass(); 
    $myInstance->lambda(); 
    
+9

giải thích Khá hoàn hảo =) – Rudie

+0

Nice, mặc dù nó sẽ được tốt đẹp để xem '__invoke /() 'vs' call_user_func' ghi chú. –

+1

Giải thích rất tốt! Rất giàu ví dụ. – Ricardo

2

Bạn cũng có thể gọi hàm lambda của bạn mà không cần một cái gì đó thay đổi trong lớp học của bạn, sử dụng ReflectionFunction.

$myInstance = new MyClass(); 
$lambda = new ReflectionFunction($myInstance->lambda); 
$lambda->invoke(); 

hoặc nếu bạn phải vượt qua đối số sau đó

$args = array('arg'=>'value'); 
$lambda->invokeArgs($args); 
+0

Đây không phải là cách ngắn nhất cũng như cách hiệu quả nhất để thực hiện nó. – amphetamachine

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