Laravel Facade实现细节考

前两天有人讲Laravel中的Facade的时候,看到了__callStatic的实现,探究了下为何如此。

现有实现

switch实现

我们在调用Facede的方法的时候,绝大多数都会被__callStatic来处理,Larvel 5.1的__callStatic实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}

这个实现是 Taylor Otwell 最初实现的版本

cufa实现

是上述switch实现的简化版:

1
return call_user_func_array([$instance, $method], $args);

Argument Unpack实现

这个是 Laravel 5.3 的实现。

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

注意,Argument Unpacking 特性在php 5.6才实现。

实现对比

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A
{
public function get()
{
return 'a';
}
}

class Facade
{
public static function __callStatic($method, $args)
{
// 待替换
}

private static function getFacadeRoot()
{
return new A();
}
}

表中为在各个情况下调用 Facede::get 100000000次的秒数

参数数量 php70+switch php70+cufa php70+unpack php56+switch php56+cufa php56+unpack
0 33 39 34 74 107 65
1 38 46 37 84 117 75
2 41 48 38 91 118 80
3 44 52 38 108 125 89
4 50 49 39 118 137 94
5 58 50 41 189 146 99
6 61 53 42 194 155 107

结论

可以看到,在PHP 5.6下,switch实现比cufa实现,在参数个数比较少的时候,有很大的优势,估计这个也是作者在第一次实现的时候,选择switch实现,而不是代码写起来更简单的cufa的原因吧。

另外,unpack在PHP 5.6下更快,但由于当时需要支持PHP 5.3,所以不能使用。
在Laravel 5.3中,由于最低PHP版本切换到了5.6.4 ,所以可以大胆的使用unpack了。

此外,实际上, PHP 7.0下,unpack在没有参数时,比switch要慢,但是个人觉得差别不大。

最后,PHP 7.0 的速度提升还是很明显的。

参考资料

https://github.com/laravel/framework/pull/12120

https://gist.github.com/nikic/6390366

作者

Robert Lu

发布于

2016-09-14

许可协议

评论