I've been looking through the laravel source code and I stumbled across this in the callStatic magic method:
switch (count($args)) {
case 0:
return $instance->$method();
case 1:
return $instance->$method($args[0]);
case 2:
return $instance->$method($args[0], $args[1]);
case 3:
return $instance->$method($args[0], $args[1], $args[2]);
case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);
default:
return call_user_func_array([$instance, $method], $args);
}
Why is the switch statement used first and then call_user_func_array()?
As Clive has mentioned in the comments; it's because of the performance concerns.
call_user_func_array()
is widely known for its performance issues. It's even slower than its sister function call_user_func()
by 10-20% as some benchmarks revealed.
Here's the result of a benchmark ran to compare the performance of straight calls vs. dynamic calls vs. calls through call_user_func*
functions:
Dynamic function calls are slightly slower than straight calls (the former have an extra interpretive layer to determine the function to call
call_user_func()
is about 50% slower, andcall_user_func_array()
is about 100% slower than a straight function call.Static and regular method calls are roughly equivalent to function calls
call_user_func()
on method calls is typically slower thancall_user_func_array()
, and the faster operation usually takes at least twice the execution time of a straight call.
— Matthew Weier O'Phinney
Paul M. Jones, another well-known PHP developer, also ran a benchmark on the exact same subject and concluded that:
So native calls to
htmlentities()
are twice as fast as doing effectively the same thing viacall_user_func()
with an object method, and usingcall_user_func_array()
is 10-20% slower than usingcall_user_func()
...Clearly, PHP has to do a lot more work behind the scenes to map the variables to objects and parameters when using
call_user_func_array()
.
— Paul M. Jones
One last thing; As of PHP 5.6 and with the advent of argument unpacking operator (AKA spread, splat or scatter operator), you can safely rewrite that code to:
$instance->$method(...$args);
Quoting from the Argument Unpacking PHP RFC:
Furthermore
call_user_func_array
has a rather large performance impact. If a large number of calls go through it, this can make a significant difference. For this reason, projects like Laravel and Drupal often replace particularly commoncall_user_func_array
calls with a switch statements.The
...
argument unpacking syntax is about 3.5 to 4 times faster thancall_user_func_args
. This solves the performance issue. Benchmark code and results.
Also, see:
Argument unpacking advantages over call_user_func_array