Laravel工程化项目四:Facade的使用

553 阅读2分钟

上一节

正文

什么是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.');

}

image.png

image.png

这里我们直接通过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就可以了。

文末福利推荐