为什么在 call_user_func_array() 之前使用 switch 语句

Why is a switch statement used before call_user_func_array()

我一直在查看 laravel 源代码,我在 callStatic 魔术方法中偶然发现了这个:

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);
}

为什么先用switch语句再用call_user_func_array()?

因为克莱夫在评论中有 ;这是因为性能问题。

call_user_func_array() 因其性能问题而广为人知。正如一些基准显示的那样,它甚至比它的姊妹函数 call_user_func()10-20%

这是基准测试的结果 运行 比较直接调用与动态调用与通过 call_user_func* 函数调用的性能:

  • 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,另一位著名的 PHP 开发人员,也是 运行 完全相同主题的基准,并得出结论:

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

参数解包

最后一件事;从 PHP 5.6 开始,使用参数解包运算符 advent(又名 spreadsplatscatter 运算符),您可以安全地将该代码重写为:

$instance->$method(...$args);

引自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.

另见:
Argument unpacking advantages over call_user_func_array