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

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