views:

229

answers:

3

How could I use call_func_array to create a new object with a __construct method (with some not optional arguments).

Here's the code:

$urls = array(
    'view' => array(
        'view/(\d+)',
        array('controller' => 'test', 'action' => 'view'),
        array(1 => 'id'),
    ),
);

foreach ($urls as $name => $args) {
  $route = call_user_func_array(Zend_Controller_Router_Route_Regex, $args);
  $router->addRoute($name, $route);
}
+1  A: 

For one, you seem to have a syntax error (as Zend_Controller_Router_Route_Regex needs to be a string.

Thus, one could think this would work:

$route = call_user_func_array(array('Zend_Controller_Router_Route_Regex', '__construct'), $args);

However, as far as I know, the first element of the array (the first parameter) can either be a string when calling a static class method or an instance of your class for any method. Neither is the case here. Thus, I would just do it this way:

$route = new Zend_Controller_Router_Route_Regex;
call_user_func_array(array('Zend_Controller_Router_Route_Regex', 'setOptions'), $args);

You might have to use array($args) instead of $args depending on the type of that variable.

EDIT No, I am wrong. There is no setOptions() function for the routes. Let me check something...

EDIT2 A rather ugly hack I found in the PHP manual regarding call_user_func_array() is the following:

$route = new Zend_Controller_Router_Route_Regex;
call_user_func_array(array($route, '__construct'), $args);

However, I did not test this and it might not work (if it can work at all) depending on the implementation of the constructor (Does it accept no parameters being passed to it? Does it just setup the class or are other things done, too?). Please tell me if it worked...

Franz
Hi, thanks for the help, it worked using $route = new Zend_Controller_Router_Route_Regex($args[0]); ugly, but works...
carlosz
What about the other arguments in the array, though?
Franz
Use the other solution. That one is great...
Franz
I meant, why only `$args[0]`? Did you not care about the rest?
Franz
I first used `$router = new object($args[0]);` just to create the object, then used `call_user_func_array(array($route, '__construct'), $args);` to fill it.
carlosz
+3  A: 

The signature for the constructor is

($route, [ $defaults = array()], [ $map = array()], [ $reverse = null])

Thus, I would have an array with the empty arguments, and merge that with the actual arguments for each router in your loop. If you want to make it simple to specify only the last option, then use string keys in your config array, and in your default array.

$blank_opts = array('', array(), array(), null); //default options and blank route

foreach ($urls as $name => $args) {
  //replaces default options with options from the array, if set
  $opts = array_replace($blank_opts, $args);
  //create the new router
  $route = new Zend_Controller_Router_Route_Regex($opts[0], $opts[1], $opts[2], $opts[3]);
  $router->addRoute($name, $route);
}
gnud
That is a really good solution. Use this instead.
Franz
+3  A: 
$ref = new ReflectionClass('Zend_Whatever');

foreach ($urls as $name => $args) {
    $route = $ref->newInstanceArgs($args);
    $router->addRoute($name, $route);
}
just somebody