最近在学习laravel框架的各种设计原理,今天看到门面模式这了,做下笔记:
Facade 工作原理
在 Laravel 应用中,门面就是一个为容器中对象提供访问方式的类。该机制原理由 Facade 类实现。Laravel 自带的门面,以及我们创建的自定义门面,都会继承自 Illuminate\Support\Facades\Facade 基类。
门面类只需要实现一个方法:getFacadeAccessor
。正是 getFacadeAccessor
方法定义了从容器中解析什么。然后 Facade 基类使用魔术方法 __callStatic()
代理门面上静态方法的调用,并将其交给通过 getFacadeAccessor
方法定义的从容器中解析出来的服务类来执行。
在config/app.php文件下有这样的配置:
'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, ],
举个栗子,lar的缓存调用是Cache::get()这样使用的,那么Cache显然是这里做了映射,那么对应的 Illuminate\Support\Facades\Cache 这个又是什么,追踪到这个类看看.
class Cache extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'cache'; } }
这个类只是继承了门面的基类 并定义了一个方法 返回一个cache名称,这里的cache其实是在app容器里能解析缓存类的对应名称.
那么Cache::get是一个怎么样的过程呢,其实在Facade类里是写了静态方法重载的,源码如下
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); } 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]; }
这里重载会去按cache的名称去容器里获取对象 最终还是去app容器里解析,然后获取对象后再调用get方法传入参数。
至于怎么把Cache对应到cache的门面上 就是用到了class_alias这个方法。
注:别名只是关联到门面类上 真正起作用的还是门面基类的重载。