2010-03-31 2 views
17

Я хотел бы динамически создать объект PHP, и параметры были бы необязательными.PHP, передающий параметры при создании нового объекта, call_user_func_array для объектов

Например, вместо того, чтобы делать это:

$test = new Obj($param); 

Я хотел бы сделать что-то вроде этого (создать новую Обь вымышленный):

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

Есть ли такая функция в PHP? Нечто похожее на call_user_func_array, но вместо объекта.

+0

, чтобы уточнить немного, имя класса является переменным (оно изменяется), а параметр $ param зависит от загружаемого класса. Иногда нет никакого параметра. Это в основном динамическая загрузка из разных классов в зависимости от ситуации. – Patrick

+0

Я думаю, что мой ответ ниже по-прежнему соответствует законопроекту из того, что вы описываете (имена переменных классов, необязательные параметры построения). Нет причин, по которым вы не можете передать null '$ param' в конструктор для класса, который ему не нужен. Если, с другой стороны, вы говорите, что тип создаваемого объекта на самом деле * зависит от '$ param' *, тогда вы захотите изучить что-то вроде Factory Pattern: http: //en.wikipedia .org/вики/Factory_method_pattern. PHP не может обрабатывать ваши решения о строительстве для вас в этом случае ... вам нужно написать логику, чтобы решить, что будет построено. – zombat

ответ

5

Вы можете динамически создавать объект до тех пор, как вы знаете имя класса:

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

Вы можете легко определить __construct() функцию взять default arguments, а если это требование вашей строительной логики.

[Редактировать заметку]: Это концепция, известная как variable variables, и есть некоторые примеры в руководстве, где вводится команда new.

16

Поскольку некоторые конструкторы могут принимать переменное количество аргументов, для его размещения следует использовать следующий метод.

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

Например, если ваш Car конструктор принял 3 арг

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

Тогда

$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

Отражение стоит дорого. Для этого вам лучше использовать 'func_get_args()'. – zombat

+4

В моих тестах с использованием отражения в php не медленнее, чем func \ _get \ _args(). Кроме того, вам не нужно менять код классов. – VolkerK

7

В таких случаях я использую фабричные методы. они могут быть легко определены в абстрактных классах:

class Foobar { 

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

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

с этим вы можете использовать call_user_func_array():

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

На основании ответа (@ Крис https://stackoverflow.com/a/2550465/1806628), здесь является использование классов отражения:

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'); 

Это полезно, если вы хотите сделать функцию копирования объекта в классе предков и не знаете, нужны ли дочерние классы в будущем или нет.

4

Вот чистая версия о том, что вы хотите:

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

Нормальный некрасиво метод создания нового экземпляра объекта с помощью нового

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

Статический вызов с использованием инициализации вместо нового

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

Статический вызов с использованием initArray вместо нового

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

В РНР 5.6, теперь вы можете добиться этого с одной строки кода, используя этот новый аргумент Распаковка оператора (...).

Вот простой пример.

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

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

См. PHP Variable-length argument lists для получения дополнительной информации.

+0

не должно быть больше 1 строки в 5.5- либо тогда. '$ db = (новый ReflectionClass ('Foo')) -> newInstanceArgs ($ args);' – hanshenrik

Смежные вопросы