Laravel 有一个类似于 Facade 设计模式的特性,也叫 Facades。这个名字可能会让你感到困惑,因为 Laravel 中的外观并没有完全实现外观设计模式。根据documentation
外观为应用程序服务容器中可用的类提供“静态”接口。
所以 Facade 将允许我们使用接口而不用担心这些接口背后的实际实现。
让我们以 Laravel 缓存系统为例。
当我们拨打$items = Cache::get('items:popular');
这里我们在 Cache 门面的帮助下从缓存中检索项目。
所有外观类都是从基础 Facade 类扩展而来的。只有一个方法,必须在每个外观类中实现:getFacadeAccessor(),它返回 IoC 容器内的唯一服务名称。所以它必须返回一个字符串,然后将其从 IoC 容器中解析出来。
这里是Illuminate\Support\Facades\Cache门面类的源代码:
<?php
namespace Illuminate\Support\Facade;
class Cache extends Facade
{
protected static function getFacadeAccessor()
{
return 'cache';
}
}
看起来我们正在调用 Cache 类的静态方法 get(),但正如我们所见,在 Cachestatic 方法/strong> 类。这里get()方法实际上存在于容器内部的服务中。所有的魔法都隐藏在基本的 Facade 类中。
在 Facade 类中,我们有 __callStatic() 方法。每次调用外观上不存在的静态方法时都会触发__callStatic()。因此,在调用Cache::get('items:popular') 之后,我们陷入了这个方法中,我们借助 getFacadeRoot() 方法从 IoC 容器中解析出外观背后的服务实例。这个方法的代码是
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);
}
方法getFacadeRoot() 返回外观背后的服务对象的实例。在这种情况下,它最终指向 CacheManager 类。在 CacheManager 类中,我们有一个 getDefaultDriver() 方法,它将从 .env 文件中获取默认缓存配置。
public function getDefaultDriver()
{
return $this->app['config']['cache.default'];
}
获取默认缓存配置后,使用__call()的PHP魔术方法尝试在默认缓存(redis、数据库、memcached等)的具体类上调用get()方法。
因此,如果默认缓存更改,我们对 $items = Cache::get('items:popular'); 的原始调用不会更改。大多数人使用 database 作为开发缓存,使用 redis 或 memcached 作为后端。 Laravel Facades 的工作是找出要执行哪些操作以从缓存中获取值。例如。 redis 的get() 实现是
public function get($key)
{
$value = $this->connection()->get($this->prefix.$key);
return ! is_null($value) ? $this->unserialize($value) : null;
}
而 memacached 的 get() 实现是
public function get($key)
{
$value = $this->memcached->get($this->prefix.$key);
if ($this->memcached->getResultCode() == 0) {
return $value;
}
}
同样,您可以使用另一个缓存具体类。 Laravel 将为您决定要调用的具体实现。