【问题标题】:Why is a switch statement used before call_user_func_array()为什么在 call_user_func_array() 之前使用 switch 语句
【发布时间】:2017-01-04 10:56:16
【问题描述】:

我一直在查看 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 比直接调用方法要慢,所以大多数情况下(最多 4 个参数)使用直接方法
  • 可能是代码没有经过任何情况,所以默认是先执行
  • 检查count($args)的值
  • 我还要说这只是一种性能优化,因为直接调用函数比使用 call_user_func_array 调用它更快

标签: php laravel switch-statement magic-methods


【解决方案1】:

因为 Clive 在 cmets 中有 mentioned;这是因为性能问题。

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

这是一个基准测试的结果,用于比较直接调用、动态调用和通过call_user_func* 函数调用的性能:

  • 动态函数调用比直接调用稍慢(前者有一个额外的解释层来确定要调用的函数 call_user_func() 比直接函数调用慢约 50%,call_user_func_array() 约慢 100%。

  • 静态和常规方法调用大致相当于函数调用 方法调用上的call_user_func() 通常比call_user_func_array() 慢,而且更快的操作通常需要至少两倍于直接调用的执行时间。
    Matthew Weier O'Phinney

另一位著名的 PHP 开发人员 Paul M. Jones 也针对完全相同的主题运行了基准测试并得出结论:

因此,对 htmlentities() 的本机调用速度是通过 call_user_func() 使用对象方法有效执行相同操作的速度的两倍,并且使用 call_user_func_array() 比使用 @ 慢 10-20% 987654338@...

显然,在使用call_user_func_array() 时,PHP 必须在后台做更多的工作来将变量映射到对象和参数。
Paul M. Jones

参数解包

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

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

引用Argument Unpacking PHP RFC

此外,call_user_func_array 具有相当大的性能影响。如果大量呼叫通过它,这可能会产生重大影响。 出于这个原因,像 Laravel 和 Drupal 这样的项目经常用 switch 语句替换特别常见的 call_user_func_array 调用

... 参数解包语法大约比 call_user_func_args3.5 到 4 倍。这解决了性能问题。基准代码和结果。

另请参阅:
Argument unpacking advantages over call_user_func_array

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多