создать экземпляр класса из переменной в 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;

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

Нет, не очень хороший пример. Работает только если все в одном и том же 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.