PHP: создание экземпляра класса из переменной странным образом не удается

Я пытаюсь создать экземпляр класса (модель Laravel3 Eloquent) с помощью переменной и получаю сообщение об ошибке, говорящее о том, что класс не найден.
Однако когда я жестко задаю имя класса, все работает нормально.
(К вашему сведению, в приведенном ниже коде $contact_type должен быть телефоном, факсом или электронной почтой.)

Вот во что я играю в данный момент:

    foreach( $input AS $contact_type => $contact_info )
    {
        foreach( $contact_info AS $data )
        {
            $obj = new $contact_type( (array)$data);
            echo'<pre>Obj: ',print_r($obj),'</pre>';  // <----- For Testing
        }
    }

Когда я запускаю код, как указано выше, он выдает ошибку "Класс "Телефон" не найден".
Когда я заменяю new $contact_type() на new Phone() (или факс или электронная почта) , работает просто отлично.
Бьюсь об заклад, есть что-то простое, я просто просматриваю :) Что я пропустил?
Пожалуйста, помогите!


person mOrloff    schedule 03.01.2014    source источник
comment
Вы случайно не в пространстве имен?   -  person deceze♦    schedule 03.01.2014
comment
@deceze - Опереди меня. Бьюсь об заклад, это все. Не могу думать ни о чем другом.   -  person Joseph Silber    schedule 03.01.2014
comment
Как здесь связано пространство имен? $obj = new Phone() также не должно работать, если пространство имен связано   -  person Royal Bg    schedule 03.01.2014
comment
@RoyalBg На самом деле, когда вы указали псевдоним пространства имен или класса в операторе USE, он будет работать при написании вручную, но не будет работать как переменная.   -  person Jessica    schedule 03.01.2014
comment
Это что-то новое для меня. Спасибо. Но почему, какая разница?   -  person Royal Bg    schedule 03.01.2014
comment
@Jessica - Не только когда useing. Классы в текущем пространстве имен также не разрешаются при использовании строки.   -  person Joseph Silber    schedule 03.01.2014
comment
@JosephSilber, я не нашел, что это правда, у меня есть код, который использует переменную для имени, и пока он находится в том же пространстве имен и не имеет псевдонима, он работает нормально.   -  person Jessica    schedule 03.01.2014
comment
Разрешены ли они, если вы создаете пространство имен со строкой? Извините, что спросил без проверки. Чуть позже протестирую. И мне все еще интересно, почему они не разрешаются с помощью строки, когда в пространстве имен   -  person Royal Bg    schedule 03.01.2014
comment
@Джессика - codepad.viper-7.com/38iklS   -  person Joseph Silber    schedule 03.01.2014
comment
@deceze Вот оно!, спасибо.   -  person mOrloff    schedule 03.01.2014


Ответы (1)


Соответствующие записи руководства, которые охватывают это, находятся здесь и здесь. Цитирую вторую ссылку:

Если строка, содержащая имя класса, используется с new, будет создан новый экземпляр этого класса. Если класс находится в пространстве имен, при этом должно использоваться его полное имя.

Это работает для меня:

class Phone {}
$classtype = 'Phone';
$phone = new $classtype();
var_dump($phone);

Производит вывод:

object(Phone)#1 (0) {
}

Убедитесь, что вы не находитесь в пространстве имен (если вы находитесь, включите пространство имен класса Phone в строку). Или вы также можете попробовать использовать отражение:

class Phone {}
$classtype = 'Phone';
$reflectionClass = new ReflectionClass($classtype);
$phone = $reflectionClass->newInstanceArgs();
var_dump($phone);

Если класс Phone находится в пространстве имен, это также работает:

Phone.php

<?php namespace Contact;

class Phone {}

test.php

<?php

include 'Phone.php';

$classtype = 'Contact\Phone';
$phone = new $classtype();
var_dump($phone);

Я не уверен на 100%, почему, хотя я подозреваю, что при оценке имени класса переменных текущие сопоставления пространств имен не видны. Рассмотрим этот код:

<?php namespace Foo;

use SomePackage\SomeClass as WeirdName;

$test = new WeirdName();

Сравните это с:

<?php namespace Foo;

use SomePackage\SomeClass as WeirdName;

$class = 'WeirdName';
$test = new $class();

Когда PHP решит выделить память для нового экземпляра, как он узнает, что нужно сопоставить псевдоним имени класса WeirdName с SomePackage\Someclass? Этот псевдоним действителен только для текущего файла, и код, который фактически выполняет эту операцию, даже не находится в пользовательский код, а тем более тот же самый файл.

person Jeff Lambert    schedule 03.01.2014
comment
Проблема заключалась в пространстве имен. У меня есть use Person\Model\Eloquent\Phone в верхней части моего скрипта (поэтому он работает, когда я вызываю new Phone()), но по какой-то причине при создании экземпляра, например new $var(), я должен определить полное пространство имен в переменной... Если кто-нибудь может объяснить, почему, Я ОЧЕНЬ заинтересован в обучении. - person mOrloff; 06.01.2014
comment
Я не уверен на 100%, почему, но я обновил свой ответ тем, что, как я подозреваю, является причиной - person Jeff Lambert; 06.01.2014
comment
Tnx, я тоже исправил это, определив пространство имен в переменной... что не так уж и плохо при работе с несколькими классами (не нужно использовать их все по отдельности). Хотя при использовании динамического имени класса с Route::model() это может привести к ошибке в вашей команде php artisan route:list. Потому что он не может найти пустую строку класса: p - person Maarten Kuijper; 26.06.2017