2013-02-04 20 views
5

Mã nói tốt hơn so với dòng chữ:namespace tương đối và call_user_func()

namespaces.php:

<?php 

namespace foo; 

use foo\models; 

class factory 
{ 
    public static function create($name) 
    { 
     /* 
     * Note 1: FQN works! 
     * return call_user_func("\\foo\\models\\$name::getInstance"); 
     * 
     * Note 2: direct instantiation of relative namespaces works! 
     * return models\test::getInstance(); 
     */ 

     // Dynamic instantiation of relative namespaces fails: class 'models\test' not found 
     return call_user_func("models\\$name::getInstance"); 
    } 
} 

namespace foo\models; 

class test 
{ 
    public static $instance; 

    public static function getInstance() 
    { 
     if (!self::$instance) { 
      self::$instance = new self; 
     } 

     return self::$instance; 
    } 

    public function __construct() 
    { 
     var_dump($this); 
    } 
} 

namespace_test.php:

<?php 

require_once 'namespaces.php'; 

foo\factory::create('test'); 

Như nhận xét, nếu tôi sử dụng tên đủ điều kiện bên trong call_user_func() nó hoạt động như mong đợi, nhưng nếu tôi sử dụng tên tương đối es nó nói rằng lớp học không được tìm thấy – nhưng các hoạt động instantiations trực tiếp. Tôi có thiếu một số thứ gì đó hoặc lạ của mình theo thiết kế?

+1

Tôi tin rằng điều này là do thiết kế. Quy tắc tương tự áp dụng cho các hàm như 'define()', 'constant()', v.v. Kiểm tra [chú thích này] (http://www.php.net/manual/en/function.defined.php#110530) . – Passerby

Trả lời

7

Bạn phải sử dụng tên lớp hoàn toàn đủ điều kiện trong các cuộc gọi lại.

Xem Example #3 call_user_func() using namespace name

<?php 

namespace Foobar; 

class Foo { 
    static public function test() { 
     print "Hello world!\n"; 
    } 
} 

call_user_func(__NAMESPACE__ .'\Foo::test'); // As of PHP 5.3.0 
call_user_func(array(__NAMESPACE__ .'\Foo', 'test')); // As of PHP 5.3.0 

Tôi tin rằng điều này là do call_user_func là một hàm từ phạm vi toàn cầu, thực hiện gọi lại từ phạm vi toàn cầu là tốt. Trong mọi trường hợp, hãy xem câu đầu tiên.

Cũng xem lưu ý ở trên Example #2 Dynamically accessing namespaced elements trong đó nêu

Một phải sử dụng tên đầy đủ (tên lớp với tiền tố namespace).

+2

Tôi đã nhìn thấy mục nhập thủ công này trước khi hỏi nhưng tôi nghĩ đó chỉ là một ví dụ, bây giờ rõ ràng đó là một quy tắc ... Đôi khi họ thiếu nhận xét tài liệu tốt hơn. Cảm ơn bạn! :) –

+1

Tôi đã thú nhận rằng tôi hoàn toàn bị mất phần ["Không gian tên và tính năng ngôn ngữ năng động"] (http://php.net/namespaces.dynamic) từ hướng dẫn ... Cảm ơn một lần nữa vì đã chỉ ra, tiếp theo tôi sẽ chú ý hơn khi đọc hướng dẫn! :) –

1

Trong các phiên bản PHP hiện tại, cách bạn sử dụng nó là cách thức - khi sử dụng chuỗi để tham chiếu tên lớp, nó cần phải đủ điều kiện với không gian tên đầy đủ. Nó không tuyệt vời, nhưng đó là cách nó được.

Trong phiên bản PHP v5.5 sắp tới, chúng sẽ bao gồm một tính năng để giải quyết vấn đề này, bằng cách cung cấp cú pháp mới Classname::class, mà bạn có thể sử dụng thay vì đặt tên lớp FQN trong một chuỗi.

Để biết thêm thông về vấn đề này, xin vui lòng xem có liên quan trang PHP RFC đây: https://wiki.php.net/rfc/class_name_scalars

Mã của bạn sẽ giống như thế này:

return call_user_func([models\$name::class,"getInstance"]); 

Đó có thể không chính xác; Tôi không có bản sao 5.5 để kiểm tra để xác nhận. Nhưng một trong hai cách, cú pháp mới sẽ làm cho mọi thứ tốt hơn rất nhiều cho các trường hợp sử dụng như của bạn.

+0

Thật tuyệt khi biết rằng họ nhận thức được điều đó và làm mọi thứ tốt hơn cho chúng tôi, cảm ơn thông tin đó! :) –