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 协议》,转载必须注明作者和本文链接
推荐文章: