2011-11-27 16 views
9

Tôi đang làm việc với các chức năng ẩn danh mà tôi đang tạo chức năng ẩn danh bên ngoài đối tượng, sau đó thêm nó vào một đối tượng sau đó, nó sẽ được sử dụng với phép thuật __callStatic chức năng. Các đóng được thêm vào để chứa các phương thức từ lớp cha. Tôi tự hỏi liệu tôi có thể gọi những phương pháp đó từ việc đóng cửa không?Chức năng ẩn danh/Đóng và sử dụng self :: hoặc static ::

Ngay bây giờ tôi nhận được lỗi này:

EmptyObject::addMethod('open', function(){ 
    if (static::_hasAdapter(get_class(), __FUNCTION__)) 
      return self::_callAdapter(get_class(), __FUNCTION__, $details); 

    echo '<p>You have mail!</p>'; 
}); 

ném lỗi này:

Fatal error: Cannot access static:: when no class scope is active in

//Add the functions 
EmptyObject::addMethod('open', function(){ 
    if (EmptyObject::_hasAdapter('EmptyObject', __FUNCTION__)) 
      return EmptyObject::_callAdapter('EmptyObject', __FUNCTION__, $details); 

    echo '<p>You have mail!</p>'; 
}); 

ném lỗi này vì phương pháp này được bảo vệ

Fatal error: Uncaught exception 'BadMethodCallException' with message 'Method '_hasAdapter' was not found in class EmptyObject'

+0

Cũ php .. Trong 5.5.9 Tôi có thể thấy 'static ::' trong hàm đồng nhất –

Trả lời

3

Closures được gọi như vậy vì một lý do. Họ 'kèm theo' phạm vi mà chúng được xác định. Chúng không chỉ đơn giản là các khối mã có thể lấy phạm vi từ nơi chúng được dán vào.

+0

Làm cho tinh thần, nhưng sau đó bạn sẽ thực hiện điều đó như thế nào mà không đưa phương pháp ra công khai? Trong javascript, bạn sẽ chỉ lưu một tham chiếu đến hàm trong một biến cục bộ và gọi nó trong phạm vi đóng. Làm thế nào để bạn làm điều này trong PHP? –

+0

Cách phạm vi hoạt động trong JavaScript và PHP là rất khác nhau. Bắt đầu từ phạm vi bên ngoài PHP không hiển thị bên trong các hàm, kết thúc bằng cách nào trong JavaScript, bạn có thể thay đổi phạm vi trong đó hàm được thực hiện. Nói cách khác: PHP không thích hợp cho việc lập trình meta như thế này. Có lẽ bạn có thể làm điều gì đó với phần mở rộng Reflection, nhưng tôi không chắc chắn về điều đó. Một cách khác sẽ được sử dụng eval có lẽ, nhưng đó có nhược điểm riêng của nó. – Mchl

13

Bạn có thể đạt được điều này bằng cách sử dụng Closure::bind() (PHP> = 5.4.0)

abstract class EmptyObject 
{ 
    protected static $methods = array(); 

    final public static function __callStatic($name, $arguments) 
    { 
     return call_user_func(self::$methods[$name], $arguments); 
    } 

    final public static function addMethod($name, $fn) 
    { 
     self::$methods[$name] = Closure::bind($fn, NULL, __CLASS__); 
    } 

    final protected static function protectedMethod() 
    { 
     echo __METHOD__ . " was called" . PHP_EOL; 
    } 
} 

Bây giờ bất kỳ chức năng ẩn danh thông qua với EmptyObject :: addMethod() sẽ được chạy trong phạm vi của lớp EmptyObject

EmptyObject::addMethod("test", function() 
{ 
    self::protectedMethod(); 
}); 


// will output: 
// EmptyObject::protectedMethod was called 

EmptyObject::test(); 
+1

Bạn nên bỏ qua đối số '__CLASS__' (hoặc đặt nó thành' 'static'', ví dụ: mặc định) trong trường hợp ràng buộc tĩnh muộn. –

+0

Điều này thật tuyệt vời! – Sean256

12

Đơn giản chỉ cần lưu tên lớp và chuyển nó đến đóng cửa qua use. Bạn có thể gọi bất kỳ phương thức tĩnh công khai nào hoặc lấy các thuộc tính tĩnh công cộng hoặc các hằng số theo cách này. Nếu việc đóng cửa được chuyển sang một ngữ cảnh khác, nó sẽ vẫn hoạt động miễn là giá trị chính xác cho $class được chuyển cho nó khi nó được tạo. Hoạt động cho php 5.3:

class test { 
    public static function callMe() { echo 'call me '; } 

    public static function runTest() { 
     $class = __CLASS__; 
     $call = function() use ($class) { 
      $class::callMe(); 
     }; 
     $call(); 
    } 
} 
test::runTest(); 
Các vấn đề liên quan