不知道如何准确命名。在深入研究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的情况,而默认情况无论如何都可以工作。
即使情况0在没有争论的情况下有意义,为什么要有情况1-4,而不仅仅是继续到情况10。这是否有合理的理由,还是只是过早优化的情况?
我怀疑这是一个微观优化。我还怀疑,大多数对facade的静态调用需要4个或更少的参数,在这种情况下,大多数静态调用不会跳到默认情况下。
我能够在call_user_func_array
上的手动条目中找到这个用户提交的报价,来自"noone at example dot com":
对于那些必须考虑性能的人来说:用这种方式调用函数的时间大约是用直接语句调用函数的3倍,所以只要可行,就应该避免这种方法
做一个非常简单的基准测试似乎也证实了这一点的有效性。结果中,1直接调用实例上的方法,2在实例上调用变量方法名,3使用call_user_func_array
,输出时间以秒为单位。每个方法的迭代次数为1000000。
$ 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
上面的结果表明,除非静态方法有4个以上的参数,否则避免call_user_func_array
可以将对静态facade方法的调用速度至少提高2倍左右。
至于为什么选择4个参数的截止数,只有Taylor知道。自从Laravel 4.0首次提交以来,这种方法(基本上)没有改变,我怀疑它有点武断。
您是对的,在不使用switch
语句的情况下调用call_user_func_array();
非常有效但是,根据这个基准,它看起来非常慢:
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
语句的原因。
因为$instance->$method()
比call_user_func_array
快。
考虑到这段代码可以在一个周期内被多次调用,因此尽可能优化它是有意义的。