23

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.

2
  • to clarify a bit more, the class name is variable (it changes), and $param depends on the class that is loaded. Sometimes there's no param. It is basically dynamically loading from a variety of classes depending on the situation. Commented Mar 31, 2010 at 3:54
  • I think my answer below still fits the bill from what you're describing (variable class names, optional construction parameters). There's no reason you can't pass a null $param to a constructor for a class that doesn't need it. If, on the other hand, you are saying that the type of object that gets created is actually dependant on $param, then you'll want to look into something like the Factory Pattern: en.wikipedia.org/wiki/Factory_method_pattern. PHP can't handle your construction decisions for you in that case... you'll need to write logic to decide what gets built. Commented Mar 31, 2010 at 4:09

6 Answers 6

28

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 Variable-length argument lists for more information.

Sign up to request clarification or add additional context in comments.

1 Comment

shouldn't need more than 1 line in 5.5- either then. $db = (new ReflectionClass ( 'Foo' ))->newInstanceArgs ( $args );
18

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

2 Comments

Reflection is expensive. You'd be better off using func_get_args() for this.
In my tests using reflection in php isn't slower than func_get_args(). Plus you don't have to change the code of the classes.
7

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

Comments

6

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.

Comments

4

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

Comments

0

Based on @chris' answer( https://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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.