How to instantiate a PHP class with dynamic parameters ?

Today I came across an interesting challenge in PHP : “How to instantiate a class with dynamic parameters ?"

Well, let’s try to explain. I need to instantiate a class with parameters provided by a yaml config file, something like this :

  class: MyClass  
  params: [ "value 1", { key1: "value key 1", key2: "value key 2" ]

so in raw php this will be done by :

  class myClass  
  {  
    public $arg1;  
    public $arg2;  

    public function __construct($arg1, $arg2)  
    {  
      $this->arg1 = $arg1;  
      $this->arg2 = $arg2;  
    }  
  }   

  $class = 'myClass';  
  $params = = array(  
    'value 1',  
    array('key1' => 'value key 1', 'key2' => 'value key 2')  
   );  

  $instance = new $class($params[0], $params[1]);

Ok now the problem is : we don’t know the number of parameters provided by the config file.

Let’s try to find a solution

Solution 1 : The bad

  function create_instance($class, $params) {  
    $inline = array();  
    foreach($params as $index => $param)  
    {  
      $params[$index] = var_export($param, true);  
    }  

    $code = 'return new '.$class.'('.implode(', ', $params).');';  

    $function = create_function('', $code);  

    return $function();  
  }  

  $instance = create_instance($class, $params);

This solution uses the create_function to instantiate the class with the correct parameters. This solution works fine with the current configuration file but will failed with object instance parameter. You will get a nice php error : ‘Call to undefined method myClass::__set_state() in index.php : runtime-created '

This error is due to var_export which try to call an non existant __set_state method to the object. This method is cleary a bad solution.

Solution 2 : The Ugly

Ok, we can say that the limit of parameters is 5. So we can do someting like this :

  function create_instance($class, $params) {  
    case(count($params)) {  
      case 0: return new $class;  
      case 1: return new $class($param[0]);  
      case 2: return new $class($param[0], $param[1]);  
      case 3: return new $class($param[0], $param[1], $param[2]);  
      // and so on ...  
    }  
  }  

  $instance = create_instance($class, $params);

This solution will work fine but it’s cleary an ugly assumption and an ugly code.

Solution 3 : The Good

The call_user_function_array() can be our friend, but there is no way to have a valid callback function with the string ‘new $class’.

My friend Ally finds the solution by using the ReflexionClass :

  function create_instance($class, $params) {  

    return call_user_func_array(  
       array(new ReflectionClass($class), 'newInstance'),  
       $params  
     );  
  }

After some look up to the ReflectionClass documentation, I find a more natural way to instantiate the class

  function create_instance($class, $params) {    
    $reflection_class = new ReflectionClass($class);  
    return $reflection_class->newInstanceArgs($params);  
  }