相对名称空间和call_user_func()

时间:2013-02-04 07:44:37

标签: php namespaces

代码说得比文字更好:

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()中使用完全限定名称,它会按预期工作,但如果我使用相对名称空间,则表示找不到类 - 但直接实例化可行。我是否因设计错过了某些内容或奇怪的

2 个答案:

答案 0 :(得分: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,其中说明了

  

必须使用完全限定名称(带名称空间前缀的类名)。

答案 1 :(得分:1)

在当前版本的PHP中,你拥有它的方式就是这样 - 当使用字符串引用类名时,它需要完全限定它的完整命名空间。这不是很好,但就是这样。

在即将发布的PHP v5.5中,它们将包含一个通过提供新的Classname::class语法来解决此问题的功能,您可以使用该语法而不是将FQN类名放在字符串中。

有关此内容的更多信息,请参阅此处的相关PHP RFC页面:https://wiki.php.net/rfc/class_name_scalars

您的代码看起来像这样:

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

这可能不准确;我没有5.5的副本来测试以确认。但无论哪种方式,新语法都会使像你这样的用例更好。