2.1 - Laravel - 5.6 - Facade - 解析机制

Facade解释

Facade 是一组静态类接口或者说代理,让开发者能简单的访问绑定到服务容器里的各种服务。

简单说就是使用一个静态类(用一个别名)直接能访问服务(就是能直接调用方法)

以一个路由举例


Route::get('/','PagesController@root')->name('root');

这里的Route我们发现找不到这个静态类,也没有路径,他能这么用其实是是使用laravel中的别名aliases机制

在文件config/app.php最下面我们可以看到

aliases的配置。

发现了对应的class.

'Route' => Illuminate\Support\Facades\Route::class,

Facade实现

基本的结构逻辑是这样的:

1. Facade 有个__callStatic方法接受所有Facede未申明的方法。比如这个例子中

Route::get(); 这个get方法在Facade中不存在直接会调用__callStatic

2. 通过这个魔术方法,寻找在存储解析后的对象中有没有一个Route的对象。

3. 找到这个对象触发这个对象的get方法。

现在我们接着进去看看这个route类,

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

这个类代码非常简单, 只提供了这个方法 getFacadeAccessor()返回router字符串而已。我们肯定想到,要去父类Facade看看。

父类方法中 $app 是一个容器

protected static $app;

resolvedInstance 是存储解析出来的Facade对应的服务类实例,这里Route真实的类实例就存在这里。索引数组,键值:Facade名称;值:服务类实例

protected static $resolvedInstance;

而此方法中并没有Route::get 对应的get方法, 其实上它call了__callStatic魔术方法

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);
}

1.这个方法中首先 getFacadeRoot 方法获取解析的对象

public static function getFacadeRoot()
{
    return static::resolveFacadeInstance(static::getFacadeAccessor());
}

1.1 getFacadeRoot()中static::getFacadeAccessor() 我们在子类中已经重写了返回的是字符串 router

1.2 进入resolveFacadeInstance方法看看

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];
}

此方法就是核心方法了:返回真实的route对象。

a.首先他判断$name是不是一个对象,我们传入的是字符串‘route’,(这样说来 我们return一个new router()对象似乎也是可以的。)
b.如果不是对象,去$resolvedInstance数组中寻找是否存在解析的route对象
c.如果有的话直接返回,如果没有,再去容器app中取route对象,同时存入resolvedInstance数组后,再返回,这样下次resolvedInstance数组中肯定就有了。
Facade就到这里获得了真实的对象。

2.如果这个对象是不存在抛出异常
3.执行这个对象中的方法 这里就是get方法。

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

关于 static::$app[$name]

  • 这个static::$app[$name] 这是怎么解析的呢。

这里使用了php的ArrayAccess 预定义接口,具体功能就是一旦实现了这个接口,就能像数组一样访问对象。这里$app是类Application的一个对象,Application又是Container的子类,Container这个类实现了ArrayAccess接口。就这样就能像数组一样取得对应的对象了。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 2

laravel并发不强,可能是太绕了

3年前 评论

auth, 为何返回的是 Illuminate\Auth\AuthManager,这个在哪里设定的?

3年前 评论
HarveyNorman (楼主) 3年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!