PHP在创建新对象时传递参数,对象调用call_user_func_array

时间:2010-03-31 03:40:55

标签: php

我想动态创建一个PHP对象,参数是可选的。

例如,而不是这样做:

$test = new Obj($param);

我想做这样的事情(创建新的ob是虚构的):

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

php中有这样的功能吗?类似于call_user_func_array的东西,但是代替对象。

6 个答案:

答案 0 :(得分:23)

从PHP 5.6开始,您现在可以使用新的Argument Unpacking运算符(...)通过一行代码实现此目的。

这是一个简单的例子。

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

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

有关详细信息,请参阅PHP Variable-length argument lists

答案 1 :(得分:16)

由于某些构造函数可能采用可变数量的参数,因此应使用以下方法来适应它。

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

例如,如果您的Car构造函数采用了3个args

$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

答案 2 :(得分: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));

答案 3 :(得分:6)

只要您知道班级名称,就可以动态创建对象:

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

如果这是构造逻辑的要求,您可以轻松定义__construct()函数以获取default arguments

[编辑注释]:这是一个称为variable variables的概念,手册中有一些例子,其中引入了new命令。

答案 4 :(得分: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();

使用init而非新

进行静态调用
echo ClassName::init('arg1', 'arg2', 'arg3')->method1()->method2();

使用initArray而不是新

进行静态调用
echo ClassName::initArray(['arg1', 'arg2', 'arg3'])->method1()->method2();

答案 5 :(得分:0)

基于@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');

如果你想在祖先类中创建一个对象复制函数并且不知道子类是否需要将来的参数,这很有用。