最近在学习laravel框架的各种设计原理,今天看到门面模式这了,做下笔记:
Facade 工作原理
在 Laravel 应用中,门面就是一个为容器中对象提供访问方式的类。该机制原理由 Facade 类实现。Laravel 自带的门面,以及我们创建的自定义门面,都会继承自 IlluminateSupportFacadesFacade 基类。
门面类只需要实现一个方法:getFacadeAccessor
。正是 getFacadeAccessor
方法定义了从容器中解析什么。然后 Facade 基类使用魔术方法 __callStatic()
代理门面上静态方法的调用,并将其交给通过 getFacadeAccessor
方法定义的从容器中解析出来的服务类来执行。
在config/app.php文件下有这样的配置:
'aliases' => [ 'App' => IlluminateSupportFacadesApp::class, 'Artisan' => IlluminateSupportFacadesArtisan::class, 'Auth' => IlluminateSupportFacadesAuth::class, 'Blade' => IlluminateSupportFacadesBlade::class, 'Broadcast' => IlluminateSupportFacadesBroadcast::class, 'Bus' => IlluminateSupportFacadesBus::class, 'Cache' => IlluminateSupportFacadesCache::class, 'Config' => IlluminateSupportFacadesConfig::class, 'Cookie' => IlluminateSupportFacadesCookie::class, 'Crypt' => IlluminateSupportFacadesCrypt::class, 'DB' => IlluminateSupportFacadesDB::class, 'Eloquent' => IlluminateDatabaseEloquentModel::class, 'Event' => IlluminateSupportFacadesEvent::class, 'File' => IlluminateSupportFacadesFile::class, 'Gate' => IlluminateSupportFacadesGate::class, 'Hash' => IlluminateSupportFacadesHash::class, 'Lang' => IlluminateSupportFacadesLang::class, 'Log' => IlluminateSupportFacadesLog::class, 'Mail' => IlluminateSupportFacadesMail::class, 'Notification' => IlluminateSupportFacadesNotification::class, 'Password' => IlluminateSupportFacadesPassword::class, 'Queue' => IlluminateSupportFacadesQueue::class, 'Redirect' => IlluminateSupportFacadesRedirect::class, 'Redis' => IlluminateSupportFacadesRedis::class, 'Request' => IlluminateSupportFacadesRequest::class, 'Response' => IlluminateSupportFacadesResponse::class, 'Route' => IlluminateSupportFacadesRoute::class, 'Schema' => IlluminateSupportFacadesSchema::class, 'Session' => IlluminateSupportFacadesSession::class, 'Storage' => IlluminateSupportFacadesStorage::class, 'URL' => IlluminateSupportFacadesURL::class, 'Validator' => IlluminateSupportFacadesValidator::class, 'View' => IlluminateSupportFacadesView::class, ],
举个栗子,lar的缓存调用是Cache::get()这样使用的,那么Cache显然是这里做了映射,那么对应的 IlluminateSupportFacadesCache 这个又是什么,追踪到这个类看看.
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这个方法。
注:别名只是关联到门面类上 真正起作用的还是门面基类的重载。