Laravel Facade实现细节考

前两天有人讲Laravel中的Facade的时候,看到了__callStatic的实现,问为何如此,所以查了一番。

现有实现

switch实现

我们在调用Facede的方法的时候,绝大多数都会被__callStatic来处理,Larvel 5.1的__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);
}

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

cufa实现

是switch实现的简化版:

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

unpack实现

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

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

这个是 Laravel 5.3 的实现。

实现对比

代码如下:

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

One thought on “Laravel Facade实现细节考”

Leave a Reply

Your email address will not be published. Required fields are marked *

25 − 22 =