2013-02-04 19 views
5

代碼說話勝於言:相對命名空間和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'); 

至於評論,如果我使用call_user_func()中的完全限定名稱,它按預期工作,但如果我使用相對名稱空間它表示該類沒有被發現–,但直接實例化的作品。我錯過了什麼或其設計奇怪

+1

我相信這是設計。同樣的規則適用於'defined()','constant()'等函數。查看[this comment](http://www.php.net/manual/en/function.defined.php#110530) 。 – Passerby

回答

7

您必須在回調中使用完全限定的類名。

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 

我相信這是因爲call_user_func是從全球範圍內的功能,執行從全球範圍內的回調也是如此。無論如何,請看第一句。

另見上面Example #2 Dynamically accessing namespaced elements說明其中規定

必須使用完全限定域名(類名命名空間前綴)。

+2

我在查詢之前看到了這個手冊條目,但我認爲這只是一個例子,現在很明顯這是一條規則......有時候它們缺少更好的文檔評論。謝謝! :) –

+1

我必須承認,我完全錯過了手冊中的[[名稱空間和動態語言功能]](http://php.net/namespaces.dynamic)部分...再次感謝您指出它,下一步當我閱讀手冊時,我會更加註意! :) –

1

在當前版本的PHP中,您擁有它的方式就是這樣 - 當使用字符串引用類名時,需要使用完整的名稱空間來完全限定它。這並不好,但事實就是這樣。

在即將推出的PHP v5.5中,它們將包含一項功能來解決這個問題,它提供了一個新的Classname::class語法,您可以使用它來代替將FQN類名放入字符串中。

有關此的詳細信息,請參見相關的RFC PHP頁面在這裏:https://wiki.php.net/rfc/class_name_scalars

您的代碼將是這個樣子:

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

這可能不準確;我沒有5.5的副本進行測試以確認。但無論哪種方式,新語法都會使您的用例更好。

+0

很高興知道他們意識到並讓我們更好,謝謝你的信息! :) –