2010-03-31 7 views
17

Me gustaría crear dinámicamente un objeto PHP, y los parámetros serían opcionales.PHP pasando parámetros al crear un objeto nuevo, call_user_func_array para objetos

Por ejemplo, en vez de hacer esto:

$test = new Obj($param); 

me gustaría hacer algo como esto (crear nueva ob es ficticio):

$test = create_new_obj('Obj', $param); 

¿Existe tal función en php? Algo similar a call_user_func_array, pero para object en su lugar.

+0

para aclarar un poco más, el nombre de clase es variable (cambia) y $ param depende de la clase que se cargue. A veces no hay param. Básicamente se carga dinámicamente desde una variedad de clases según la situación. – Patrick

+0

Creo que mi respuesta a continuación todavía se ajusta a lo que está describiendo (nombres de clases variables, parámetros de construcción opcionales). No hay ninguna razón por la que no pueda pasar un '$ param' nulo a un constructor para una clase que no lo necesita. Si, por otro lado, está diciendo que el tipo de objeto que se crea depende realmente de '$ param' *, entonces querrá ver algo como el patrón de fábrica: http: //en.wikipedia .org/wiki/Factory_method_pattern. PHP no puede manejar tus decisiones de construcción para ti en ese caso ... necesitarás escribir lógica para decidir qué se construye. – zombat

Respuesta

5

Puede crear dinámicamente un objeto, siempre y cuando se conoce el nombre de la clase:

$objName = 'myClass'; 
$test = new $objName($param); 

Desde aquí se puede definir una función para tomar __construct()default arguments así si eso era un requisito de la lógica de la construcción.

[Editar nota]: Este es un concepto conocido como variable variables, y hay algunos ejemplos en el manual donde se introduce el comando new.

16

Dado que algunos constructores pueden tomar una cantidad variable de argumentos, se debe usar el siguiente método para acomodarlo.

$r = new ReflectionClass($strClassName); 
$myInstance = $r->newInstanceArgs($arrayOfConstructorArgs); 

Por ejemplo, si su Car constructor tomó 3 args

$carObj = new Car($color, $engine, $wheels); 

Entonces

$strClassName = 'Car'; 
$arrayOfConstructorArgs = array($color, $engine, $wheels); 
$r = new ReflectionClass($strClassName); 
$carObj = $r->newInstanceArgs($arrayOfConstructorArgs); 

http://php.net/manual/en/class.reflectionclass.php
http://php.net/manual/en/reflectionclass.newinstanceargs.php

+0

La reflexión es costosa. Sería mejor usar 'func_get_args()' para esto. – zombat

+4

En mis pruebas usando la reflexión en php no es más lento que func \ _get \ _args(). Además, no tienes que cambiar el código de las clases. – VolkerK

7

En tales casos i uso de la fábrica-métodos. que pueden ser fácilmente definidos en las clases abstractas:

class Foobar { 

    public function __construct($foo, $bar) 
    { 
     // do something 
    } 

    static public function factory($foo, $bar) 
    { 
     return new self($foo, $bar); 
    } 
} 

con ello se puede utilizar call_user_func_array():

$my_foobar_obj = call_user_func_array('Foobar::factory', array($foo, $bar)); 
0

Basado en respuesta @ Chris (https://stackoverflow.com/a/2550465/1806628), aquí es un uso de las clases de reflexión:

abstract class A{ 
    // the constructor writes out the given parameters 
    public function __construct(){ 
     var_dump(func_get_args()); 
    } 

    public function copy(){ 
     // find our current class' name, __CLASS__ would return A 
     $thisClass = get_class($this); 
     $tmp = new ReflectionClass($thisClass); 
     // pass all the parameters recieved to the new object 
     $copy = $tmp->newInstanceArgs(func_get_args()); 

     return $copy; 
    } 
} 

class B extends A{} 

// create a new B object, with no parameters 
$b = new B(); 

// create another b, but with other parameters 
$c = $b->copy('the parameter of the copied B'); 

Esto es útil, si desea hacer una función de copia de objetos en una clase ancestra y no sabe, si las clases secundarias necesitan parámetros en el futuro, o no.

4

Aquí es una versión limpia de lo que quería:

class ClassName { 
    public static function init(){  
     return (new ReflectionClass(get_called_class()))->newInstanceArgs(func_get_args());   
    } 

    public static function initArray($array=[]){  
     return (new ReflectionClass(get_called_class()))->newInstanceArgs($array);   
    } 

    public function __construct($arg1, $arg2, $arg3){ 
     ///construction code 
    } 
} 

método fea normal de crear una nueva instancia de un objeto utilizando las nuevas

$obj = new ClassName('arg1', 'arg2', 'arg3'); 
echo $obj->method1()->method2(); 

llamada estática con init en lugar de nueva

echo ClassName::init('arg1', 'arg2', 'arg3')->method1()->method2(); 

llamada estática con initArray vez de nuevo

echo ClassName::initArray(['arg1', 'arg2', 'arg3'])->method1()->method2(); 
20

A partir de PHP 5.6, ahora se puede lograr esto con una sola línea de código utilizando el operador Desembalaje nuevo argumento (...).

Aquí hay un ejemplo simple.

$className='Foo'; 
$args=['arg1','arg2','arg3']; 

$newClassInstance=new $className(...$args); 

Consulte PHP Variable-length argument lists para obtener más información.

+0

no debería necesitar más de 1 línea en 5.5- tampoco entonces. '$ db = (new ReflectionClass ('Foo')) -> newInstanceArgs ($ args);' – hanshenrik

Cuestiones relacionadas