【问题标题】:Relative namespaces and call_user_func()相对命名空间和 call_user_func()
【发布时间】:2013-01-18 21:27:03
【问题描述】:

代码胜于雄辩:

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

【问题讨论】:

  • 我相信这是设计使然。相同的规则适用于defined()constant() 等函数。查看this comment

标签: php namespaces


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

【讨论】:

  • 很高兴知道他们意识到这一点并让我们做得更好,感谢您提供的信息! :)
【解决方案2】:

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

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 说明

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

【讨论】:

  • 我在询问之前看过这个手册条目,但我认为这只是一个例子,现在很明显这是一个规则......有时他们缺乏更好的文档 cmets。谢谢! :)
  • 我不得不承认我完全错过了手册中的"Namespaces and dynamic language features"部分...再次感谢您的指出,下次我阅读手册时会更加注意! :)
猜你喜欢
  • 2011-03-20
  • 2022-12-31
  • 1970-01-01
  • 2010-10-20
  • 2013-01-20
  • 1970-01-01
  • 1970-01-01
  • 2018-05-01
  • 1970-01-01
相关资源
最近更新 更多