什么是门面
门面为应用服务容器中可用的类提供了「静态」接口。Laravel 内置了大量门面,几乎覆盖了框架的所有功能。 Laravel 的门面充当服务容器内实际类的「静态代理」,在保持易测性和灵活性的同时,也提供了比传统静态方法更简洁、更富表达力的语法。 所有 Laravel 门面都定义在Illuminate\Support\Facades 命名空间下。
即使不完全理解门面的原理也没关系。先记住用法继续学习 Laravel 即可。
门面的工作原理
在 Laravel 应用中,门面是一种提供访问容器中对象的类。这一机制由Facade 类实现。Laravel 所有门面(以及自定义门面)都继承基类 Illuminate\Support\Facades\Facade。
基类 Facade 通过 __callStatic() 魔术方法,把对门面的调用转发给容器解析出的实际对象。
Cache 门面。该门面代理对 Illuminate\Contracts\Cache\Factory 接口实现的访问。所有通过门面进行的调用都会转发到 Laravel 缓存服务的内部实例上。
查看 Illuminate\Support\Facades\Cache 类可以发现,它并没有静态方法 get。
Cache 门面继承自基类 Facade 并实现了 getFacadeAccessor() 方法。该方法返回容器中的绑定名。当用户调用 Cache 门面的静态方法时,Laravel 会从服务容器中解析 cache 绑定,然后在该对象上执行所请求的方法(如 get)。
何时使用门面,何时避免使用
门面的优点
门面有很多优点:无需记住繁长的类名,也不必手动注入或配置,就能以简洁易记的语法使用 Laravel 功能。此外,凭借 PHP 动态方法的独特用法,门面非常易于测试。注意「作用范围蔓延」
使用门面的主要风险是类的「作用范围蔓延(scope creep)」。因为门面易于使用且无需注入,类很容易膨胀并持续使用大量门面。使用依赖注入时,庞大的构造器能带来直观的反馈。使用门面时,请留意类的规模,将职责范围保持在较小的范围内。门面 vs. 依赖注入
依赖注入的主要好处之一是可以替换被注入类的实现,这在测试时非常有用。你可以注入 mock 或 stub,然后断言其上的方法被以何种方式调用。 通常真正的静态方法难以 mock 或 stub,但门面借助动态方法把调用转发给服务容器解析出的对象,所以对门面进行测试就和测试注入的类实例一样简单。Cache::get 被以预期参数调用。
门面 vs. 辅助函数
除了门面,Laravel 还提供了执行常见任务(如生成视图、触发事件、派发任务、发送 HTTP 响应等)的「辅助函数」。许多辅助函数的功能与其对应的门面相同。实时门面
使用实时门面,可以将应用中的任意类当作门面使用。先看一个没有使用实时门面的例子。 例如,Podcast 模型有一个 publish 方法。但发布 podcast 需要注入一个 Publisher 实例。
Publisher 实例,同时也保持了同等的可测试性。要生成实时门面,只需在要导入的类的命名空间前加上 Facades 前缀即可。
Facades 前缀后面的接口或类名,从服务容器解析出对应的实现。
测试门面
测试门面时使用shouldReceive 方法,会返回一个 Mockery mock 实例。由于门面实际上是通过服务容器解析和管理的,因此比普通静态类更易于测试。
| 方法 | 说明 |
|---|---|
shouldReceive('method') | 期望方法被调用 |
once() | 期望只调用 1 次 |
times(n) | 期望调用 n 次 |
with(args) | 期望以特定参数调用 |
andReturn(value) | 返回指定值 |
andReturnNull() | 返回 null |
常用门面一览
以下是常用门面与其对应实际类、服务容器绑定名的对照表。| 门面 | 类 | 绑定 |
|---|---|---|
App | Illuminate\Foundation\Application | app |
Auth | Illuminate\Auth\AuthManager | auth |
Cache | Illuminate\Cache\CacheManager | cache |
Config | Illuminate\Config\Repository | config |
Cookie | Illuminate\Cookie\CookieJar | cookie |
Crypt | Illuminate\Encryption\Encrypter | encrypter |
DB | Illuminate\Database\DatabaseManager | db |
Event | Illuminate\Events\Dispatcher | events |
File | Illuminate\Filesystem\Filesystem | files |
Gate | Illuminate\Contracts\Auth\Access\Gate | — |
Hash | Illuminate\Contracts\Hashing\Hasher | hash |
Http | Illuminate\Http\Client\Factory | — |
Log | Illuminate\Log\LogManager | log |
Mail | Illuminate\Mail\Mailer | mailer |
Notification | Illuminate\Notifications\ChannelManager | — |
Queue | Illuminate\Queue\QueueManager | queue |
RateLimiter | Illuminate\Cache\RateLimiter | — |
Redirect | Illuminate\Routing\Redirector | redirect |
Request | Illuminate\Http\Request | request |
Route | Illuminate\Routing\Router | router |
Schema | Illuminate\Database\Schema\Builder | — |
Session | Illuminate\Session\SessionManager | session |
Storage | Illuminate\Filesystem\FilesystemManager | filesystem |
URL | Illuminate\Routing\UrlGenerator | url |
Validator | Illuminate\Validation\Factory | validator |
View | Illuminate\View\Factory | view |
下一步
Contracts(契约)
了解与门面成对的 Contracts 概念及选择方式。