Относительные пространства имен и 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() он работает так, как ожидалось, но если я использую относительные пространства имен, то говорит, что класс не был найден, но работают прямые экземпляры. Я что-то упускаю или странно по дизайну?

Вы должны использовать полное имя класса в обратных вызовах.

См. Пример №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 для проверки с подтверждением. Но в любом случае новый синтаксис сделает вещи намного лучше для таких случаев, как ваши.