跳转到主要内容

什么是门面

门面为应用服务容器中可用的类提供了「静态」接口。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 前缀即可。
使用实时门面时,Laravel 会根据 Facades 前缀后面的接口或类名,从服务容器解析出对应的实现。
当希望简化测试 mock,同时避免将依赖作为参数显式传递时,实时门面非常方便。

测试门面

测试门面时使用 shouldReceive 方法,会返回一个 Mockery mock 实例。由于门面实际上是通过服务容器解析和管理的,因此比普通静态类更易于测试。
常用的 mock 方法如下:

常用门面一览

以下是常用门面与其对应实际类、服务容器绑定名的对照表。

下一步

Contracts(契约)

了解与门面成对的 Contracts 概念及选择方式。
最后修改于 2026年7月18日