上一节
正文
什么是Facade
Facade按照翻译就是门面,你可能听说过有一种设计模式叫Facade模式,没错就是这个。通俗的说服务提供者通过Facade向客户端隐藏了实现细节,暴露给客户端需要的方法,客户端不需要关系内部构造,调用需要的方法就可以了。
来看代码,对于Cache的使用通常是这样的,在Api/IndexController.php中
public function cacheGet()
{
return $this->apiSuccess([
'yname' => Cache::get('yname')
]);
}
public function cacheSet()
{
if (Cache::add('yname', 'jack')) {
return $this->apiSuccess();
}
return $this->apiFail('cache set fail.');
}
这里我们直接通过src/Illuminate/Support/Facades/Cache.php 对Cache进行操作,而不需要关心Cache的实现逻辑,如存到哪里、如何存储的,这是Facade的特点、功能。
Facade是怎么实现的
还是以Cache的例子来看,可以看到Facades/Cache.php就几行代码,它暴露了一些方法供客户端使用:
/**
* @method static \Illuminate\Cache\TaggedCache tags(array|mixed $names)
* @method static \Illuminate\Contracts\Cache\Lock lock(string $name, int $seconds = 0, mixed $owner = null)
* @method static \Illuminate\Contracts\Cache\Lock restoreLock(string $name, string $owner)
* @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null)
* @method static \Illuminate\Contracts\Cache\Store getStore()
* @method static bool add(string $key, $value, \DateTimeInterface|\DateInterval|int $ttl = null)
* @method static bool flush()
* @method static bool forever(string $key, $value)
* @method static bool forget(string $key)
* @method static bool has(string $key)
* @method static bool missing(string $key)
* @method static bool put(string $key, $value, \DateTimeInterface|\DateInterval|int $ttl = null)
* @method static int|bool decrement(string $key, $value = 1)
* @method static int|bool increment(string $key, $value = 1)
* @method static mixed get(string $key, mixed $default = null)
* @method static mixed pull(string $key, mixed $default = null)
* @method static mixed remember(string $key, \DateTimeInterface|\DateInterval|int $ttl, \Closure $callback)
* @method static mixed rememberForever(string $key, \Closure $callback)
* @method static mixed sear(string $key, \Closure $callback)
*
* @see \Illuminate\Cache\CacheManager
* @see \Illuminate\Cache\Repository
*/
class Cache extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'cache';
}
}
来看Facade父类中的几个方法就能明白他的实现原理了:
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*
* @throws \RuntimeException
*/
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);
}
/**
* Get the root object behind the facade.
*
* @return mixed
*/
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
/**
* Resolve the facade root instance from the container.
*
* @param object|string $name
* @return mixed
*/
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) {
return $name;
}
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
if (static::$app) {
return static::$resolvedInstance[$name] = static::$app[$name];
}
}
哈哈,也就是我们操作Cache::get时,实际上是调用app中的cache实例进行操作。
app中的cache是如何来的呢,这就用到了我们上一节提到的CacheServiceProvider了, 我们看到src/Illuminate/Cache/CacheServiceProvider.php的逻辑:
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('cache', function ($app) {
return new CacheManager($app);
});
$this->app->singleton('cache.store', function ($app) {
return $app['cache']->driver();
});
$this->app->singleton('cache.psr6', function ($app) {
return new Psr16Adapter($app['cache.store']);
});
$this->app->singleton('memcached.connector', function () {
return new MemcachedConnector;
});
$this->app->singleton(RateLimiter::class, function ($app) {
return new RateLimiter($app->make('cache')->driver(
$app['config']->get('cache.limiter')
));
});
}
这里你可能明白了, cache 在这里与 CacheManager进行绑定。
综上所述 Cache::get 最终操作的还是 CacheManage 的 get 方法,具体CacheManger的实现细节:怎么初始化的、驱动是咋选的等等这里不再讨论,有需要可以留言讨论奥。
Facade在Laravel的内部存在大量的使用,但因为Facade的类是对多个背后类的封装,所以我们尽量不去新增Facade,可以通过接口实现去扩展自己需要的功能。而且artisan中也没有提供Facade的创建模板,这里我们了解如何使用内部Facade就可以了。
文末福利推荐
- 本文代码:github.com/nobody05/la…
- 参考文档:learnku.com/docs/larave…
- 外卖领券,感谢关注😁