Создание объекта из переменной с использованием пространств имен и автозагрузки в PHP - PullRequest
17 голосов
/ 31 октября 2011

РЕДАКТИРОВАТЬ с моим собственным комментарием впоследствии

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

Конец редактирования

Я использую 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

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

Спасибо!


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

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

Ответы [ 3 ]

7 голосов
/ 31 октября 2011

Интересный вопрос. Судя по всему, нет никакого способа обойти это. 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();
1 голос
/ 01 ноября 2011

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

// This may be working because Symfony's 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's autloader should have picked this up, but didn't
// It's possible that with this construct Symfony cannot find the class and b/c
// it's not namespaced, PHP has no choice but to fail
$controller_name = "Index";
$controller3     = new $controller_name();

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

0 голосов
/ 01 ноября 2011

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

use Controller\Home\Index as Index;

, а затем

$controller3 = new Index();

- это то же самое, что случилось со мной с сервисом Zend amazon S3. Я решил это с помощью:

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

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

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

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