eine Klasse aus einer Variablen in PHP instanziieren?

146

Ich weiß, dass diese Frage ziemlich vage klingt, deshalb werde ich sie anhand eines Beispiels klarer machen:

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

Das möchte ich tun. Wie würdest du es machen? Ich könnte natürlich eval () so verwenden:

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

Aber ich halte mich lieber von eval () fern. Gibt es eine Möglichkeit, dies ohne eval () zu tun?

Pim Jäger
quelle

Antworten:

213

Fügen Sie den Klassennamen zuerst in eine Variable ein:

$classname=$var.'Class';

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

Dies ist oft die Art von Dingen, die Sie in einem Factory-Muster sehen werden.

Weitere Informationen finden Sie unter Namespaces und dynamische Sprachfunktionen .

Paul Dixon
quelle
2
So mache ich es. Beachten Sie, dass Sie innerhalb von Klassen Eltern und Selbst verwenden können.
Ross
1
In ähnlicher Weise können Sie auch $ var = 'Name' ausführen. $ obj -> {'get'. $ var} ();
Mario
1
Guter Punkt, obwohl das nur für Methodenaufrufe und nicht für Konstruktoren funktioniert
Paul Dixon
12
Wenn Sie mit einem Namespace arbeiten, $var = __NAMESPACE__ . '\\' . $var . 'Class';
fügen
@bastey - aber warum? Ich habe einfach zu viel Zeit damit verbracht herauszufinden, warum dies ohne den Namespace vor dem Klassennamen nicht funktionieren würde ...
jkulak
72

Wenn Sie Namespaces verwenden

Nach meinen eigenen Erkenntnissen ist es gut zu erwähnen, dass Sie (soweit ich das beurteilen kann) den vollständigen Namespace-Pfad einer Klasse deklarieren müssen.

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
quelle
6
Die einzige funktionierende Lösung, die mit einem Namespace erstellt werden muss, ist Ihre. Danke fürs teilen!
Tiago Gouvêa
Aber das ist einfach komisch. Warum sollte es nicht den deklarierten Namespace verwenden?
Israel Dov
@YisraelDov Ja, es ist definitiv kontraintuitiv. Aber aus irgendeinem Grund verhält es sich in diesem Zusammenhang seltsam. Vielen Dank php
csga5000
@YisraelDov Ich denke, das liegt daran, dass in diesem Fall das Instanziieren einer Klasse aus einem anderen Namespace große Kopfschmerzen verursachen würde. Beachten Sie auch, dass Variablen weitergegeben werden können. Wenn der Klassenname als Text in eine PHP-Datei geschrieben wird, weiß jeder, der ihn schreibt, genau, in welchen Namespace er geschrieben ist. Wenn jedoch eine Variable zwischen Funktionen übergeben wird, wäre es ein Albtraum, sie weiterzuverfolgen. Auch wenn Sie get_class () verwenden, wird der FQ-Klassenname zurückgegeben, sodass dieser sofort in einer Variablen gespeichert und überall verwendet werden kann. Wenn es vom Namespace der Datei abhängen würde, würde es nicht sehr gut funktionieren.
sbnc.eu
61

So übergeben Sie auch dynamische Konstruktorparameter

Wenn Sie dynamische Konstruktorparameter an die Klasse übergeben möchten, können Sie diesen Code verwenden:

$reflectionClass = new ReflectionClass($className);

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

Weitere Informationen zu dynamischen Klassen und Parametern

PHP> = 5,6

Ab PHP 5.6 können Sie dies mit Argument Unpacking noch weiter vereinfachen :

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

Vielen Dank an DisgruntledGoat für den Hinweis.

Grippe
quelle
7
Von PHP 5.6 Sie sollten Verwendung Argument auspacken können:new $className(...$params)
DisgruntledGoat
29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes
zalew
quelle
Nein, kein gutes Beispiel. Funktioniert nur, wenn sich alles in derselben PHP-Datei befindet.
Fralbo
2
2ndGAB sollte diesen Kommentar entfernen. Autoloading hat mit dieser Frage nichts zu tun.
Jim Maguire
-1

Ich würde die call_user_func()oder call_user_func_arrayPHP-Methoden empfehlen . Sie können sie hier überprüfen ( call_user_func_array , call_user_func ).

Beispiel

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

Wenn Sie Argumente haben, die Sie an die Methode übergeben, verwenden Sie die call_user_func_array()Funktion.

Beispiel.

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
quelle
3
Diese Antwort gilt nicht für die Frage. OP fragt, wie eine Klasse (die die Methode __construct dynamisch auslöst) aus einer Variablenzeichenfolge INSTANTIIERT und das KLASSENOBJEKT in eine neue Variable zurückgegeben wird. Ihr Rat gibt den Wert der Klasse-> Methode ([]) zurück, die Sie ' Beim erneuten Aufruf gilt nicht das Klassenobjekt, daher gilt dies nicht für diesen Fall. Siehe den Rückgabewert php.net/manual/en/function.call-user-func-array.php
ChrisN