【问题标题】:PHP Laravel Facade __callStatic argument listPHP Laravel Facade __callStatic 参数列表
【发布时间】:2026-01-01 05:40:01
【问题描述】:

不确定如何准确命名。在深入研究 Laravel 4 类以了解 Facades 的工作原理时,我偶然发现了这一点:

Illuminate\Support\Facades\Facades.php@__callStatic

public static function __callStatic($method, $args)
{
    $instance = static::getFacadeRoot();

    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(array($instance, $method), $args);
    }
}

现在据我所知,此方法调用 Facade 引用的类的任何给定方法并传递参数。我可能是错的,但这是我目前的理解。

真正困扰我的部分是开关。

当默认情况下无论如何都可以工作时,为什么需要情况 0 到 4。

即使 case 0 在没有参数的情况下是有意义的,为什么还要有 case 1-4 而不仅仅是继续 case 10。这是否有合理的论据,还是只是过早优化的情况?

【问题讨论】:

    标签: php optimization laravel arguments


    【解决方案1】:

    我怀疑这是一个微优化。我还怀疑这些对外观的静态调用中的大多数将需要 4 个或更少的参数,在这种情况下,大多数静态调用不会跳转到默认情况。

    我能够在 call_user_func_array 的手动条目中从“noone at example dot com”中找到这个用户提交的报价:

    对于那些必须考虑性能的人:以这种方式调用函数所需的时间大约是通过直接语句调用的 3 倍,因此只要可以避免这种方法,这样做是一个明智的主意。

    做一个非常简单的基准测试似乎也证实了这一点的有效性。结果中,1是直接调用实例上的方法,2是调用实例上的变量方法名,3是使用call_user_func_array,输出时间以秒为单位。每种方法的迭代次数为 1,000,000。

    $ php test.php  
    (1) total: 0.51281404495239 
    (2) total: 0.51285219192505 
    (3) total: 1.1298811435699 
    $ php test.php  
    (1) total: 0.49811697006226 
    (2) total: 0.5209321975708 
    (3) total: 1.1204349994659 
    $ php test.php  
    (1) total: 0.48825788497925 
    (2) total: 0.51465392112732 
    (3) total: 1.156769990921
    

    以上结果表明,避免使用call_user_func_array 可以将静态外观方法的调用速度至少提高大约 2 倍,除非静态方法的参数超过 4 个。

    至于为什么选择 4 个参数的截止数,只有 Taylor 知道。自 Laravel 4.0 的 first commit 以来,该方法(大部分)没有改变,我怀疑它有些武断。

    【讨论】:

      【解决方案2】:

      你是对的,调用call_user_func_array(); 可以完美地工作,而无需使用switch 语句。 但是,根据这个benchmark,它似乎非常慢:

      function html($value)
      {
          return htmlentities($value);
      }
      
      name            : diff     : total    : description
      native          : 0.614219 : 0.613295 : htmlentities($value)
      literal_func    : 0.745537 : 1.346594 : html($value)
      variable_func   : 0.826048 : 2.162376 : $func($value)
      literal_method  : 0.957708 : 3.127519 : $object->html($value)
      variable_method : 0.840837 : 3.970290 : $object->$func($value)
      call_func       : 1.006599 : 4.993930 : call_user_func($func, $value)
      call_object     : 1.193323 : 6.215677 : call_user_func((array($object, $func), $value)
      cufa_func       : 1.232891 : 7.320287 : call_user_func_array($func, array($value))
      cufa_object     : 1.309725 : 8.769755 : call_user_func_array((array($object, $func), array($value)
      

      所以基本上这只会在您多次使用call_user_func_array() 时才会成为问题(在 Laravel 中就是这种情况)。这就是他们使用switch 声明的原因。

      【讨论】:

        【解决方案3】:

        因为$instance->$method()call_user_func_array方式

        鉴于这段代码可以在一个周期内多次调用,因此尽可能对其进行优化是有意义的。

        【讨论】: