Я хотел бы динамически создать объект PHP, и параметры были бы необязательными.
Например, вместо этого:
$test = new Obj($param);
Я хотел бы сделать что-то вроде этого (создать новое ob является вымышленным):
$test = create_new_obj('Obj', $param);
Есть ли такая функция в php? Нечто похожее на call_user_func_array, но вместо объекта.
Начиная с PHP 5.6, вы можете достичь этого с помощью одной строки кода, используя новый оператор Argument Unpacking (…).
Вот простой пример.
$className='Foo'; $args=['arg1','arg2','arg3']; $newClassInstance=new $className(...$args);
Подробнее см. В списках аргументов переменной длины PHP .
Поскольку некоторые конструкторы могут принимать переменное количество аргументов, для его размещения следует использовать следующий метод.
$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
В таких случаях я использую фабричные методы. они могут быть легко определены в абстрактных классах:
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));
Вы можете динамически создавать объект, если знаете имя класса:
$objName = 'myClass'; $test = new $objName($param);
Вы можете легко определить функцию __construct()
чтобы принимать аргументы по умолчанию, если это было требованием вашей логики построения.
[Редактировать заметку]: это понятие, известное как переменные переменные , и есть некоторые примеры в руководстве, где вводится новая команда.
Вот чистая версия того, что вы хотели:
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();
Основываясь на ответе @chris ( 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');
Это полезно, если вы хотите сделать функцию копирования объекта в классе предков и не знаете, нужны ли дочерние классы в будущем, или нет.