9

代码胜于雄辩:

命名空间.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()它会按预期工作,但如果我使用相对名称空间,它会说找不到该类——但直接实例化是有效的。我是否遗漏了某些东西,或者它的设计很奇怪

4

2 回答 2

11

您必须在回调中使用完全限定的类名。

请参阅使用命名空间名称的示例 #3call_user_func()

<?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它是来自全局范围的函数,也执行来自全局范围的回调。无论如何,请参见第一句话。

另请参阅上面的注释示例 #2 动态访问命名空间元素,其中声明

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

于 2013-02-04T07:50:34.580 回答
2

在当前版本的 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 的副本可供测试以确认。但无论哪种方式,新语法都会让你的用例变得更好。

于 2013-02-04T10:28:26.417 回答