收录日期:2021/01/22 01:59:57 时间:2010-03-31 03:40:54 标签:php

I would like to dynamically create a PHP object, and parameters would be optional.

For example, instead of doing this:

$test = new Obj($param);

I would like to do something like this (create new ob is fictional):

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

Is there such function in php? Something similar to call_user_func_array, but for object instead.

Since some constructors may take a variable number of arguments, the following method should be used to accommodate it.

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

For example, if your Car constructor took 3 args

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

Then

$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

In such cases i use factory-methods. they can be easily defined in abstract classes:

class Foobar {

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

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

with this you can use call_user_func_array():

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

As of PHP 5.6, you can now achieve this with a single line of code by using the new Argument Unpacking operator (...).

Here is a simple example.

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

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

See PHP Argument Unpacking for more information.

You can dynamically create an object as long as you know the class name:

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

You could easily define a __construct() function to take default arguments as well if that was a requirement of your construction logic.

[Edit note]: This is a concept known as variable variables, and there's some examples in the manual where the new command is introduced.

Here is a clean version of what you wanted:

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

Normal ugly method of creating a new object instance using new

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

Static call using init instead of new

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

Static call using initArray instead of new

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

Based on @chris' answer( http://stackoverflow.com/a/2550465/1806628 ), here is a usage of reflection classes:

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

This is useful, if you want to make an object copy function in an ancestor class and don't know, whether child classes need parameters in the future, or not.