PHP, передающий параметры при создании нового объекта, call_user_func_array для объектов
Я хотел бы динамически создать объект PHP, и параметры были бы необязательными.
Например, вместо этого:
$test = new Obj($param);
Я хотел бы сделать что-то вроде этого (создать новое ob является вымышленным):
$test = create_new_obj('Obj', $param);
Есть ли такая функция в php? Что-то похожее на call_user_func_array, но вместо этого на объект.
Ответы
Ответ 1
Начиная с PHP 5.6, вы можете достичь этого с помощью одной строки кода, используя новый оператор Argument Unpacking (...).
Вот простой пример.
$className='Foo';
$args=['arg1','arg2','arg3'];
$newClassInstance=new $className(...$args);
Подробнее см. Список аргументов переменной длины.
Ответ 2
Так как некоторые конструкторы могут принимать переменное количество аргументов, для его размещения следует использовать следующий метод.
$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
Ответ 3
В таких случаях я использую factory -методы. они могут быть легко определены в абстрактных классах:
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));
Ответ 4
Вы можете динамически создавать объект, если знаете имя класса:
$objName = 'myClass';
$test = new $objName($param);
Вы можете легко определить функцию __construct()
, чтобы принять аргументы по умолчанию, если это было требованием вашей логики построения.
[Редактировать заметку]: это понятие, известное как переменные переменные , а также некоторые примеры в руководстве, где new.
Ответ 5
Вот чистая версия того, что вы хотели:
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();
Статический вызов с использованием init вместо нового
echo ClassName::init('arg1', 'arg2', 'arg3')->method1()->method2();
Статический вызов с использованием initArray вместо нового
echo ClassName::initArray(['arg1', 'arg2', 'arg3'])->method1()->method2();
Ответ 6
На основе ответа @chris (fooobar.com/info/299195/...), это использование классов отражения:
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');
Это полезно, если вы хотите сделать функцию копирования объекта в классе предков и не знаете, нужны ли дочерние классы в будущем или нет.