2

Assume that there is a function with some parameters and I have an associative array (or a simple object with public properties - which is almost the same, since I can always use a type cast (object)$array) whose keys correspond to the function parameter names and whose values correspond to function call arguments. How do I call it and pass them in there?

<?php
function f($b, $a) { echo "$a$b"; }
// notice that the order of args may differ.
$args = ['a' => 1, 'b' => 2];
call_user_func_array('f', $args); // expected output: 12 ; actual output: 21
f($args); // expected output: 12 ; actual output: ↓
// Fatal error: Uncaught ArgumentCountError:
// Too few arguments to function f(), 1 passed
whyer
  • 783
  • 5
  • 16

2 Answers2

3

It turns out, I just had to use variadic function named param unpacking feature introduced in PHP 8 ( https://wiki.php.net/rfc/named_params#variadic_functions_and_argument_unpacking ) :

f(...$args); // output: 12

Prior to PHP 8, this code produces the error: Cannot unpack array with string keys.

Secondly, it turns out that call_user_func_array also works as expected in PHP 8 (see https://wiki.php.net/rfc/named_params#call_user_func_and_friends for explanation):

call_user_func_array('f', $args); // output: 12

- while it still outputs incorrect '21' in older versions.

whyer
  • 783
  • 5
  • 16
1

As a hack for older versions of PHP you could also use Reflection:

<?php
function test($b, $a) {
  echo "$a$b";
}

$callback = 'test';

$parameters = ['a' => 1, 'b' => 2];

$reflection = new ReflectionFunction($callback);
$new_parameters = array();

foreach ($reflection->getParameters() as $parameter) {
  $new_parameters[] = $parameters[$parameter->name];
}

$parameters = $new_parameters;

call_user_func_array($callback, $parameters);

Demo

Urmat Zhenaliev
  • 1,497
  • 8
  • 22
  • yeah, i've thought of this as well, but it looks a little bit overcomplicated for seemingly such a simple thing. but for older php versions it's probably the only working solution. but i think it's too much and maybe is a sign that one rather shouldn't use passing parameters as an assoc.array at all than use it with reflection, imo – whyer Dec 27 '20 at 16:09
  • 1
    That is why I noted `As a hack`. I also do not like this solution. But it's really weird that till now it was impossible to use associative array for `call_user_func` – Urmat Zhenaliev Dec 28 '20 at 04:00