інстанціювати клас зі змінної в 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 ()?

Відповіді:


214

Спершу поставте ім'я класу в змінну:

$classname=$var.'Class';

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

Це часто така штука, яку ви побачите, загорнутий у заводський зразок.

Докладніші відомості див. У просторах імен та динамічних функціях мови .


2
Ось як я це роблю. Зауважте, що з класів ви можете використовувати батьківські та самості.
Росс

1
На подібній ноті ви також можете зробити $ var = 'Ім'я'; $ obj -> {'get'. $ var} ();
Маріо

1
Хороший момент, хоча це працює лише для викликів методів, а не для конструкторів
Пол Діксон

12
Якщо ви працюєте з простором імен, $var = __NAMESPACE__ . '\\' . $var . 'Class';
введіть

@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.
fralbo

2
2ndGAB повинен видалити цей коментар. Автозавантаження не має нічого спільного з цим питанням.
Jim Maguire

-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.