Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamic function arguments

Tags:

php

I'm passing all my calls to a main mapping function and then it should dynamically call other function based on a string (until this part, things are easy) the problem is that I want to pass arguments to the second function and these parameters may vary. The following is given (should not be changed):

function test1($x){
     echo $x;
}

function test2($x, $y){
     echo $x * $y;
}

and now comes the mapping function

function mapping ($str){
      switch ($str){
          case 'name1':
              $fn_name = 'test1';
              $var = 5;
              break;
          case 'name2':
              $fn_name = 'test2';
              $var = 5;
              break;
      }
      $this->{$fn_name}($var);
}

And then this will run the mapping:

$this->mapping('name1');
$this->mapping('name2');   // This one will crash as it need two variables

Of course the above is simplified to focus on the problem not the purpose of the code. The problem is when the function has more than one argument (which can easily happen). I'm expecting to have the switch case and based on how the case parameters are filled, the line $this->{$fn_name}($var); should work.

Can you please advise or give me ideas, knowing that the functions (test1, test2) structure can NOT be changed. I can NOT suddenly start using func_get_args() or func_get_arg()

like image 535
bhefny Avatar asked Oct 30 '10 22:10

bhefny


2 Answers

You can use ReflectionFunction and its invokeArgs() method to pass the variables in an array:

function mapping ($str) {
    switch ($str) {
        case 'name1':
            $fn_name = 'test1';
            $fn_args = array(5);
            break;
        case 'name2':
            $fn_name = 'test2';
            $fn_args = array(5, 10);
            break;
    }

    $function = new ReflectionFunction($fn_name);
    $function->invokeArgs($fn_args);
}
like image 170
Tatu Ulmanen Avatar answered Oct 10 '22 10:10

Tatu Ulmanen


Since mapping() in your code seems to be a class method, replace it with:

public function __call($method, $args)
{
    // possibly validate $method first, e.g. with a static map
    return call_user_func_array($method, $args);
}

Examples:

function foo($foo) { echo $foo; }
function bar($foo, $bar) { echo "$foo - $bar"; }

$this->foo('foo'); // outputs 'foo'
$this->bar('foo', 'bar'); // outputs 'foo - bar'

This means that your class shouldn't have the methods foo() or bar() for the __call() to be invoked.

Seems to be a pretty complicated problem though. There's probably a more elegant solution to what you're trying to achieve? :)

like image 22
Till Avatar answered Oct 10 '22 11:10

Till