instanciar una clase de una variable en PHP?

146

Sé que esta pregunta suena bastante vaga, así que lo dejaré más claro con un ejemplo:

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

Esto es lo que quiero hacer. ¿Como lo harias? Por supuesto, podría usar eval () así:

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

Pero prefiero mantenerme alejado de eval (). ¿Hay alguna manera de hacer esto sin eval ()?

Pim Jager
fuente

Respuestas:

215

Ponga el nombre de clase en una variable primero:

$classname=$var.'Class';

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

Esto es a menudo el tipo de cosas que verás envuelto en un patrón Factory.

Consulte Espacios de nombres y funciones de lenguaje dinámico para obtener más detalles.

Paul Dixon
fuente
2
Así es como lo hago. Tenga en cuenta que desde dentro de las clases puede usar parent y self.
Ross
1
En una nota similar, también puede hacer $ var = 'Nombre'; $ obj -> {'get'. $ var} ();
Mario
1
Buen punto, aunque eso solo funciona para llamadas a métodos y no para constructores
Paul Dixon
12
Si trabaja con el espacio de nombres, coloque el espacio de nombres actual en la cadena:$var = __NAMESPACE__ . '\\' . $var . 'Class';
bastey
@bastey, pero ¿por qué? Me acabo de pasar demasiado tiempo en averiguar, por qué esto no funcionaría sin el espacio de nombres que precede al nombre de la clase ...
jkulak
72

Si usa espacios de nombres

En mis propios hallazgos, creo que es bueno mencionar que usted (por lo que puedo decir) debe declarar la ruta completa del espacio de nombres de una clase.

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
fuente
66
La única solución de trabajo cuando se necesita crear con un espacio de nombres es la suya. ¡Gracias por compartir!
Tiago Gouvêa
Pero esto es extraño, ¿por qué no usaría el espacio de nombres declarado?
Israel Dov
@YisraelDov Sí, definitivamente es contra intuitivo. Pero por alguna razón, se comporta de manera extraña en este contexto. Gracias php
csga5000
@YisraelDov Supongo que es porque en ese caso crear instancias de una clase de otro espacio de nombres sería un gran dolor de cabeza. También considere que las variables se pueden pasar. Cuando el nombre de clase se escribe como texto en un archivo php, quien lo escriba sabe exactamente en qué espacio de nombre está escrito. Pero cuando se pasa una variable entre funciones, sería una pesadilla hacer un seguimiento. Además, si usa get_class () devolverá el nombre de clase FQ, por lo que puede almacenarse en una variable de inmediato y usarse en cualquier lugar. Si dependiera del espacio de nombres del archivo, no funcionaría muy bien.
sbnc.eu
61

Cómo pasar parámetros dinámicos de constructor también

Si desea pasar los parámetros del constructor dinámico a la clase, puede usar este código:

$reflectionClass = new ReflectionClass($className);

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

Más información sobre clases y parámetros dinámicos.

PHP> = 5.6

A partir de PHP 5.6 puede simplificar esto aún más mediante el uso de Argument Unpacking :

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

Gracias a DisgruntledGoat por señalar eso.

gripe
fuente
77
Desde PHP 5.6 debería poder usar el desempaquetado de argumentos:new $className(...$params)
DisgruntledGoat
29
class Test {
    public function yo() {
        return 'yoes';
    }
}

$var = 'Test';

$obj = new $var();
echo $obj->yo(); //yoes
zalew
fuente
No, no es un buen ejemplo. Solo funciona si todo está en el mismo archivo php.
fralbo
2
2ndGAB debería eliminar este comentario. La carga automática no tiene nada que ver con esta pregunta.
Jim Maguire
-1

Recomendaría los métodos call_user_func()o call_user_func_arrayphp. Puede consultarlos aquí ( call_user_func_array , call_user_func ).

ejemplo

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

Si tiene argumentos que está pasando al método, entonces use la call_user_func_array()función.

ejemplo.

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
fuente
3
Esta respuesta no se aplica a la pregunta. OP está preguntando cómo INSTANTIAR una clase (activando el método de construcción de clase __ dinámicamente) desde una cadena variable y obteniendo el OBJETO DE CLASE en una nueva variable: su consejo devolverá el VALOR del método clase-> ([]) usted ' llama, no el objeto de clase, por lo que no se aplica para este caso. Vea el valor de retorno php.net/manual/en/function.call-user-func-array.php
ChrisN