2010-03-31 9 views
17

Mi piacerebbe creare dinamicamente un oggetto PHP, ei parametri sarebbero facoltativi.Parametri di passaggio PHP durante la creazione di un nuovo oggetto, call_user_func_array per gli oggetti

Ad esempio, invece di fare questo:

$test = new Obj($param); 

mi piacerebbe fare qualcosa di simile (creare un nuovo ob è di fantasia):

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

Esiste tale funzione in php? Qualcosa di simile a call_user_func_array, ma per oggetto invece.

+0

per chiarire un po 'di più, il nome della classe è variabile (cambia), e $ param dipende dalla classe che viene caricata. A volte non ci sono parametri. È fondamentalmente il caricamento dinamico da una varietà di classi a seconda della situazione. – Patrick

+0

Penso che la mia risposta di seguito rispecchi ancora il conto di ciò che stai descrivendo (nomi di classi variabili, parametri di costruzione facoltativi). Non c'è motivo per cui non si possa passare un '$ param' nullo a un costruttore per una classe che non ne ha bisogno. Se, d'altra parte, stai dicendo che il tipo di oggetto che viene creato è in realtà * dipendente da '$ param' *, allora ti consigliamo di esaminare qualcosa come il Pattern di fabbrica: http: //en.wikipedia .org/wiki/Factory_method_pattern. PHP non può gestire le tue decisioni di costruzione per te in quel caso ... dovrai scrivere una logica per decidere cosa viene costruito. – zombat

risposta

5

È possibile creare in modo dinamico un oggetto fino a quando si conosce il nome della classe:

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

Si potrebbe facilmente definire una funzione __construct() di prendere default arguments pure se fosse un requisito della logica di costruzione.

[Modifica nota]: questo è un concetto noto come variable variables e alcuni esempi nel manuale in cui è stato introdotto il comando new.

16

Poiché alcuni costruttori possono utilizzare un numero variabile di argomenti, è necessario utilizzare il seguente metodo per adattarlo.

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

Ad esempio, se il costruttore Car voluti 3 args

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

Poi

$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 riflessione è costosa. Faresti meglio a usare 'func_get_args()' per questo. – zombat

+4

Nei miei test l'uso di reflection in php non è più lento di func \ _get \ _args(). Inoltre non devi modificare il codice delle classi. – VolkerK

7

In questi casi i uso della fabbrica-metodi. possono essere facilmente definiti in classi astratte:

class Foobar { 

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

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

Con questo si può utilizzare call_user_func_array():

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

in base alla risposta @ Chris (https://stackoverflow.com/a/2550465/1806628), ecco un utilizzo di classi di riflessione:

Ciò è utile, se si desidera eseguire una funzione di copia di un oggetto in una classe di antenato e non si sa, se le classi figlio necessitano di parametri in futuro o meno.

4

Ecco una versione pulita di ciò che si voleva:

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

normale brutto metodo di creazione di una nuova istanza di oggetto utilizzando nuova

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

chiamata statico tramite init invece di nuovo

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

chiamata statico utilizzando initArray invece di nuovo

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

partire da PHP 5.6, è ora possibile raggiungere questo obiettivo con una sola riga di codice utilizzando il nuovo argomento dell'operatore Apertura della confezione (...).

Ecco un semplice esempio.

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

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

Vedi PHP Variable-length argument lists per ulteriori informazioni.

+0

non dovrebbe richiedere più di 1 riga in 5.5- allora. '$ db = (nuovo ReflectionClass ('Foo')) -> newInstanceArgs ($ args);' – hanshenrik

Problemi correlati