Код говорит лучше, чем слова:
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()
он работает так, как ожидалось, но если я использую относительные пространства имен, то говорит, что класс не был найден, но работают прямые экземпляры. Я что-то упускаю или странно по дизайну?
Вы должны использовать полное имя класса в обратных вызовах.
См. Пример №3 call_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 Динамический доступ к элементам с именами, которые указывают
Необходимо использовать полное имя (имя класса с префиксом пространства имен).
В текущих версиях 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 для проверки с подтверждением. Но в любом случае новый синтаксис сделает вещи намного лучше для таких случаев, как ваши.