создать экземпляр класса из переменной в PHP?

146

Я знаю, что этот вопрос звучит довольно расплывчато, поэтому я поясню это на примере:

$var = 'bar';
$bar = new {$var}Class('var for __construct()'); //$bar = new barClass('var for __construct()');

Это то, что я хочу сделать. Как бы вы это сделали? Конечно, я мог бы использовать eval () следующим образом:

$var = 'bar';
eval('$bar = new '.$var.'Class(\'var for __construct()\');');

Но я бы предпочел держаться подальше от eval (). Есть ли способ сделать это без eval ()?

Пим Ягер
источник

Ответы:

215

Сначала поместите имя класса в переменную:

$classname=$var.'Class';

$bar=new $classname("xyz");

Это часто то, что вы увидите в фабричном шаблоне.

См. Пространства имен и функции динамического языка для получения дополнительной информации.

Пол Диксон
источник
2
Вот как я это делаю. Обратите внимание, что внутри классов вы можете использовать parent и self.
Росс
1
На аналогичную заметку вы также можете сделать $ var = 'Name'; $ OBJ -> { 'получить' $ вар.} ();
Марио
1
Хороший вопрос, хотя это работает только для вызовов методов, а не конструкторов
Пол Диксон
12
Если вы работаете с пространством имен, поместите текущее пространство имен в строку:$var = __NAMESPACE__ . '\\' . $var . 'Class';
bastey
@ Bastey - но почему? Я просто потратил слишком много времени на выяснение, почему это не сработало бы без пространства имен, предшествующего имени класса ...
jkulak
72

Если вы используете пространства имен

В моих собственных выводах я думаю, что хорошо упомянуть, что вы (насколько я могу судить) должны объявить полный путь к пространству имен класса.

MyClass.php

namespace com\company\lib;
class MyClass {
}

index.php

namespace com\company\lib;

//Works fine
$i = new MyClass();

$cname = 'MyClass';

//Errors
//$i = new $cname;

//Works fine
$cname = "com\\company\\lib\\".$cname;
$i = new $cname;
csga5000
источник
6
Единственное рабочее решение, когда нужно создать с пространством имен, это ваше. Спасибо за акцию!
Tiago Gouvêa
Но это просто странно. Почему бы не использовать объявленное пространство имен?
Исраэль Дов
@YisraelDov Да, это определенно нелогично. Но по какой-то причине он ведет себя странно в этом контексте. Спасибо php
csga5000
@YisraelDov Я думаю, это потому, что в этом случае создание экземпляра класса из другого пространства имен будет огромной головной болью. Также учтите, что переменные могут передаваться. Когда имя класса записывается в виде текста в php-файл, тот, кто пишет, точно знает, в какое пространство имен он записан. Но когда переменная передается между функциями, это будет кошмаром для нее. Также, если вы используете get_class (), он вернет имя класса FQ, чтобы его можно было сразу сохранить в переменной и использовать где угодно. Если бы это зависело от пространства имен файла, это не сработало бы очень хорошо.
sbnc.eu
61

Как передать параметры динамического конструктора тоже

Если вы хотите передать динамические параметры конструктора в класс, вы можете использовать этот код:

$reflectionClass = new ReflectionClass($className);

$module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);

Больше информации о динамических классах и параметрах

PHP> = 5.6

Начиная с PHP 5.6 вы можете упростить это еще больше, используя распаковку аргумента :

// The "..." is part of the language and indicates an argument array to unpack.
$module = new $className(...$arrayOfConstructorParameters);

Спасибо DisgruntledGoat за указание на это.

грипп
источник
7
Из PHP 5.6 вы сможете использовать распаковку аргументов:new $className(...$params)
DisgruntledGoat
29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes
Zalew
источник
Нет, не очень хороший пример. Работает только если все в одном и том же php файле.
фральбо
2
2ndGAB должен удалить этот комментарий. Автозагрузка не имеет ничего общего с этим вопросом.
Джим Магуайр
-1

Я бы порекомендовал методы call_user_func()или call_user_func_arrayPHP. Вы можете проверить их здесь ( call_user_func_array , call_user_func ).

пример

class Foo {
static public function test() {
    print "Hello world!\n";
}
}

 call_user_func('Foo::test');//FOO is the class, test is the method both separated by ::
 //or
 call_user_func(array('Foo', 'test'));//alternatively you can pass the class and method as an array

Если у вас есть аргументы, передаваемые методу, используйте call_user_func_array() функцию.

пример.

class foo {
function bar($arg, $arg2) {
    echo __METHOD__, " got $arg and $arg2\n";
}
}

// Call the $foo->bar() method with 2 arguments
call_user_func_array(array("foo", "bar"), array("three", "four"));
//or
//FOO is the class, bar is the method both separated by ::
call_user_func_array("foo::bar"), array("three", "four"));
пикман мурими
источник
3
Этот ответ не относится к вопросу. OP спрашивает, как УСТАНОВИТЬ класс (динамически вызывая метод класса __construct) из строки переменной и возвращая ОБЪЕКТ КЛАССА обратно в новую переменную - ваш совет вернет ЗНАЧЕНИЕ метода class-> ([]), который вы ' Вызывается, а не объект класса, поэтому не применяется для этого случая. См. Возвращаемое значение php.net/manual/en/function.call-user-func-array.php
ChrisN