9

Was wondering if it's possible to make a call like func_get_args() (reference) but instead of resulting in a 0-index array, result in an associative array, using the variable names as the keys?

For example:

function foo($arg1, $arg2)
{
    var_dump(func_get_args());
}

foo('bar1', 'bar2');

// Output
array(2) {
  [0]=>
  string(4) "bar1"
  [1]=>
  string(4) "bar2"
}

// Preferred
array(2) {
  [arg1]=>
  string(4) "bar1"
  [arg2]=>
  string(4) "bar2"
}

The reason I ask, is I need to validate that these args, passed as an array, to a RPC function, are actually populated. And it seems to be it's better to be specific about the contents rather than hoping they were passed in correct order:

// Now
if (array_key_exists(0, $args)) {

// Preferred
if (array_key_exists('arg1', $args)) {

It would be easy for me to create an assoc array from the args passed in to the original function before passing off to RPC, but was just wondering if there were an already compiled function to do it for me.

Thanks.

-- Edit --

Sorry, I forgot to mention that the code I am touching already exists, which means I cannot change the function signature.

Mike Purcell
  • 19,847
  • 10
  • 52
  • 89
  • 2
    PHP has no named parameters, which is why you can't pass them in as such. So what you are actually looking for is to order an associative array before you pass it in per call_user_func_array? – mario Feb 08 '12 at 18:54
  • 2
    Please see [How can I convert a PHP function's parameter list to an associative array?](http://stackoverflow.com/q/1419467/367456) and [Can I pass an associative array as an argument to ReflectionMethod::invokeArgs?](http://stackoverflow.com/q/8649536/367456). – hakre Feb 08 '12 at 20:27
  • @hakre: Thanks man, the first link is what I was looking for (get_defined_vars()). I read through php docs and couldn't find this, seems like they should have it as a link from func_get_args() doc page. I'm cool with closing this question, or if you want to post as an answer, that works too. – Mike Purcell Feb 08 '12 at 21:01
  • @Mario: Sorry, I forgot to mention that it is existing code, which means I cannot change the signature. – Mike Purcell Feb 08 '12 at 21:01
  • @MikePurcell: Added an answer with some more information to better decide between the both. – hakre Feb 08 '12 at 21:56

2 Answers2

28

You can make use of get_defined_varsDocs at the very beginning of your function so that it contains only the passed (and defined) arguments:

function foo($arg1, $arg2)
{
    var_dump(get_defined_vars());
}

foo('bar1', 'bar2');

Output (Demo on 3v4l.org):

array(2) {
  ["arg1"]=>
  string(4) "bar1"
  ["arg2"]=>
  string(4) "bar2"
}

If you're making use of static or global variables inside the function, specify them after you call get_defined_vars, e.g.:

function foo($arg1, $arg2)
{
    $passed = get_defined_vars();

    static $staticVariable = 0;
    global $globalVariable;
    ...
}

Take care that this is not the same as func_get_argsDocs which will also contain passed but not defined function arguments. Also default arguments aren't part of func_get_args but naturally get_defined_vars will have them with their default value.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • Thanks, this worked exactly as described, and allowed me to validate against specific, named keys, vs int keys. Not doing any global scope resolution with these values, just passing them around to various functions. – Mike Purcell Feb 08 '12 at 21:56
5

You should require that the arguments themselves not be arguments, but rather, an associative array:

public function yourMethod(array $args = array()) {
    if (array_key_exists('foo', $args)) {
        // foo
    }

    // ...
}

$obj->yourMethod(array(
    'foo' => 'foo value',
    'bar' => 'bar value'
));
FtDRbwLXw6
  • 27,774
  • 13
  • 70
  • 107
  • +1 ... I would probably change `if (array_key_exists('foo', $args))` to the better performing `if (isset($args['foo']))` –  Feb 08 '12 at 18:54
  • Was just typing the same answer. +1 – vascowhite Feb 08 '12 at 18:54
  • @rdlowrey: That works for some cases, but in others, the mere presence of the key is important, and `isset()` will return `FALSE` if the value is `NULL`, even if the key exists. – FtDRbwLXw6 Feb 08 '12 at 18:56
  • 1
    @drrcknlsn Totally agree, I guess I expect the OP to understand how `isset` works. Probably not a safe assumption in general, though. It's the sort of operation I would use a ternary for: `$foo = isset($args['foo']) ? $args['foo'] : NULL;` in order to safely use the faster `isset` –  Feb 08 '12 at 18:59
  • Agreed, and this is what I do most of the time, however (my mistake), I forgot to mention in the OP that this is already existing code, which means I cannot change the signature from args to an array. – Mike Purcell Feb 08 '12 at 20:50