utworzyć instancję klasy ze zmiennej w PHP?

146

Wiem, że to pytanie brzmi dość niejasno, więc wyjaśnię je na przykładzie:

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

To jest to, co chcę zrobić. Jak byś to zrobił? Oczywiście mógłbym użyć eval () w ten sposób:

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

Ale wolałbym trzymać się z dala od eval (). Czy można to zrobić bez eval ()?

Pim Jager
źródło

Odpowiedzi:

214

Najpierw umieść nazwę klasy w zmiennej:

$classname=$var.'Class';

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

Często jest to coś, co można zobaczyć w formie fabrycznej.

Aby uzyskać więcej informacji, zobacz Przestrzenie nazw i funkcje języka dynamicznego .

Paul Dixon
źródło
2
Tak to robię. Zauważ, że w ramach zajęć możesz używać rodzica i siebie.
Ross
1
Podobnie możesz zrobić $ var = 'Name'; $ obj -> {'get'. $ var} ();
Mario
1
Dobra uwaga, chociaż działa to tylko dla wywołań metod, a nie konstruktorów
Paul Dixon,
12
Jeśli pracujesz z przestrzenią nazw, umieść bieżącą przestrzeń nazw w ciągu:$var = __NAMESPACE__ . '\\' . $var . 'Class';
bastey
@bastey - ale dlaczego? Po prostu spędziłem zbyt dużo czasu na zastanawianiu się, dlaczego to nie zadziała bez przestrzeni nazw poprzedzającej nazwę klasy ...
jkulak
72

Jeśli używasz przestrzeni nazw

W moich własnych ustaleniach myślę, że dobrze jest wspomnieć, że (o ile wiem) musisz zadeklarować pełną ścieżkę przestrzeni nazw klasy.

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
źródło
6
Jedynym działającym rozwiązaniem, gdy trzeba tworzyć z przestrzenią nazw, są Twoje. Dziękuję za udostępnienie!
Tiago Gouvêa
Ale to jest po prostu dziwne, dlaczego nie miałoby używać zadeklarowanej przestrzeni nazw?
Yisrael Dov
@YisraelDov Tak, jest to zdecydowanie sprzeczne z intuicją. Ale z jakiegoś powodu zachowuje się dziwnie w tym kontekście. Dzięki php
csga5000
@YisraelDov Wydaje mi się, że dzieje się tak dlatego, że w takim przypadku utworzenie instancji klasy z innej przestrzeni nazw byłoby ogromnym bólem głowy. Weź również pod uwagę, że zmienne mogą być przekazywane. Kiedy nazwa klasy jest zapisywana jako tekst w pliku php, ktokolwiek ją zapisze, wie dokładnie, w jakiej przestrzeni nazw jest zapisana. Ale kiedy zmienna jest przekazywana między funkcjami, śledzenie jej byłoby koszmarem. Ponadto, jeśli użyjesz get_class (), zwróci ona nazwę klasy FQ, dzięki czemu można ją od razu przechowywać w zmiennej i używać w dowolnym miejscu. Gdyby zależało to od przestrzeni nazw pliku, nie działałoby to zbyt dobrze.
sbnc.eu
61

Jak również przekazywać parametry konstruktora dynamicznego

Jeśli chcesz przekazać do klasy parametry konstruktora dynamicznego, możesz użyć tego kodu:

$reflectionClass = new ReflectionClass($className);

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

Więcej informacji o klasach i parametrach dynamicznych

PHP> = 5.6

Od PHP 5.6 możesz to jeszcze bardziej uprościć używając Rozpakowywanie argumentów :

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

Dziękuję DisgruntledGoat za wskazanie tego.

grypa
źródło
7
Od PHP 5.6 powinno być możliwe rozpakowywanie argumentów:new $className(...$params)
DisgruntledGoat
29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes
zalew
źródło
Nie, nie jest to dobry przykład. Działa tylko wtedy, gdy wszystko jest w tym samym pliku php.
fralbo
2
2ndGAB powinien usunąć ten komentarz. Automatyczne ładowanie nie ma nic wspólnego z tym pytaniem.
Jim Maguire
-1

Chciałbym polecić call_user_func()lub call_user_func_arrayphp metod. Możesz je sprawdzić tutaj ( call_user_func_array , call_user_func ).

przykład

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

Jeśli masz argumenty, które przekazujesz do metody, użyj call_user_func_array()funkcji.

przykład.

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"));
pickman murimi
źródło
3
Ta odpowiedź nie dotyczy pytania. OP pyta, jak NATYCHMIASTOWAĆ klasę (dynamicznie wyzwalając metodę class __construct) z ciągu zmiennej i otrzymując OBIEKT KLASY z powrotem w nowej zmiennej - twoja rada zwróci WARTOŚĆ klasy-> metoda ([]) ty ' ponowne wywołanie, a nie obiekt klasy, więc nie ma zastosowania w tym przypadku. Zobacz wartość zwracaną php.net/manual/en/function.call-user-func-array.php
ChrisN