你知道Laravel中Facade为什么这样实现?

20 篇文章 0 订阅

Route::get('/', function () {
    return view('welcome');
});

在laravel中的路由文件routes/web.php有这么一段代码,用于配置路由。这里Route就是用Facade实现类方法get的静态调用。

Laravel中的Facade解决类什么问题?

在php中,很多情况都需要使用一个容器获取到所有的对象,然后再调用改对象的方法,这样在编写代码的时候就会看到很长的一个调用链。例如:
在Yii2中,几乎所有的系统类都是在app容器当中,对这些系统类进行操作都需要执行Yii::$app->route获取到类实例,然后在执行方法Yii::$app->route->get()。但是如果用Facade实现之后的调用就是Route::get()。这样的写法是的代码更加简洁。

Laravel中Facade是怎么实现的?

思路是通过__callStatic魔术方法将方法调用代理到实际的对象方法中去。


abstract class Facade
{
    ...
    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }
    ...
    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        return static::$resolvedInstance[$name] = static::$app[$name];
    }
    ...
    public static function getFacadeAccessor(){
        //子类返回类名
    }
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

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

class Route extends Facade{
    public static function getFacadeAccessor(){
        return 'router';
    }
}

根据每个Facade中提供的getFacadeAccessor返回实际的对象类名,获取类对象。每个类对象一旦创建,就放在一个静态数组中,因此在一次请求中最多只会被创建一次。

有没有其他的实现方式?

从上面的代码可以看到,其实核心就是一个静态代理的功能。那么有没有其他的实现方式了呢?

class Facade{
    public static $instance;
    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }
    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$instance)) {
            return static::$instance;
        }

        return static::$instance = static::$app[$name];
    }
    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

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

class Route extends Facade{

}

可以看出,上面的方式也能够实现静态代理,类似于Facade的功能。都是通过魔术方法实现。作用上,都简化了代码编写。

两种不同实现方式的区别

第二种实现方式有一个很大的缺点,那就是必须继承Facade类。PHP本身只能继承一个类,所以第二种实现方式对于一些需要继承其他类的对象是不适合的。

Laravel的实现方式,对类本身没有束缚,任何类对象都能够通过创建一个Facade对象实现静态代理。有很大的灵活性。

文章有【写PHP的老王】发表,更多内容可关注公号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值