Подтвердить что ты не робот

Создание объекта из переменной с использованием пространств имен и автозагрузки в PHP

EDIT с моим собственным комментарием после

Я думаю, проблема в том, что когда PHP разбирает файл для "компиляции", сначала он переводит имена классов в их полностью квалифицированные имя. Таким образом, индекс будет переведен в Controller\Home\Index. После что, когда PHP переводит переменные в их значение. Поэтому, если я использую переменная как имя класса, она не будет определять свое имя, потому что это шаг уже произошел. И вот почему не находит класс. Это просто предположение, но, скорее всего, именно так Blockquote

Редактировать конец

Im, использующий UniversalClassLoader из проекта Symfony2 для автоматической загрузки моих классов, но я обнаружил некоторую странную ошибку, которую я не могу решить.

Функция автоматической загрузки работает нормально, но затем я столкнулся с этой проблемой:

$controller      = new Index(); // It works!

$controller_name = "Controller\\Home\\Index";
$controller2     = new $controller_name(); // It works!

$controller_name = "Index";
$controller3     = new $controller_name(); // Fatal error: Class 'Index' not found

Два первых случая работают отлично. В первом, так как я использую "use Controller\Home;" в начале моего script я могу использовать только "новый Index();" без проблем. Но если вместо "Индекса" я использую строчную переменную типа $var = "Index", она НЕ работает. Я не понимаю, почему. Мне нужно, чтобы этот script был динамическим, поэтому для этого мне нужна переменная.

Спасибо!


<суб > дополнительные поиски длинного хвоста:

  • php полное имя из переменной
  • PHP-экземпляр класса из псевдонима в переменной

суб >

4b9b3361

Ответ 1

Интересный вопрос. По внешнему виду, нет никакого способа обойти это. В php docs явно указано следующее:

Необходимо использовать полное имя (имя класса с префиксом пространства имен).

Возможным обходным решением в вашем случае будет определение базового пространства имен для ваших контроллеров в конфигурации и регистрация контроллеров по их относительному пространству имен.

Предположим, что базовое пространство имен MyApp\Controller\, и мы будем держать наши контроллеры в массиве (для краткости):

$controllers = array(
    'foo/bar' => 'MyFooController',
    'baz'     => 'Foo\\MyBarController'
);

// One way how the controllers could be instantiated:

// returns 'MyApp\\Controller\\'
$namespace = $cfg->get('namespaces.controller');

$controller = $namespace.$controllers['baz'];
$controller = new $controller();

Ответ 2

Интервал имен означает, что PHP не только сможет найти файл с заданным путем (в значительной степени такой же, как и require_once), но и имя класса также соответствует директиве пространства имен. Единственный diff? Слэши для подчеркивания (пример № 2 ниже).

// This may be working because Symfony autoloader has found a class named Index
$controller      = new Index(); 

// A name-space call so PHP knows where to actually find the file
// Chances are the class name here is Controller_Home_Index
$controller_name = "Controller\\Home\\Index";
$controller2     = new $controller_name();

// Symfony autloader should have picked this up, but didn't
// It possible that with this construct Symfony cannot find the class and b/c
// it not namespaced, PHP has no choice but to fail
$controller_name = "Index";
$controller3     = new $controller_name();

Проверьте директорию кэша проекта Symfony, есть и некоторые плоские файлы массивов PHP, которые могут вам помочь.

Ответ 3

Вы пробовали:

use Controller\Home\Index as Index;

а затем

$controller3 = new Index();

- это то же самое, что случилось со мной с Zend Amazon S3 Service. Я решил это, используя:

use Zend\Service\Amazon\S3\S3 as Zend_Service_Amazon_S3;

$s3 = new Zend_Service_Amazon_S3($key, $secret);

Конечно, после того, как имена будут помещены в файл автозагрузки следующим образом:

'Zend'                => __DIR__.'/../vendor/Zend/library',