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

时间:2017-01-04 10:56:17

标签: php laravel switch-statement magic-methods

我一直在浏览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()?

1 个答案:

答案 0 :(得分:3)

正如克莱夫在评论中有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%慢于使用call_user_func() ...

     

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

参数解包

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

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

引用Argument Unpacking PHP RFC

  

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

     

...参数解包语法约 call_user_func_args快3.5到4倍。这解决了性能问题。基准代码和结果。

另见:
Argument unpacking advantages over call_user_func_array