Why is a switch statement used before call_user_func_array()

235 views Asked by At

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()?

1

There are 1 answers

0
sepehr On BEST ANSWER

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, and call_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 than call_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 via call_user_func() with an object method, and using call_user_func_array() is 10-20% slower than using call_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

Argument Unpacking

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 common call_user_func_array calls with a switch statements.

The ... argument unpacking syntax is about 3.5 to 4 times faster than call_user_func_args. This solves the performance issue. Benchmark code and results.

Also, see:
Argument unpacking advantages over call_user_func_array