Facades
- Introduction
- When to Utilize Facades
- How Facades Work
- Real-Time Facades
- Facade Class Reference
Introduction
Throughout the Laravel documentation, you will see examples of code that interacts with Laravel’s features via “facades”. Facades provide a “static” interface to classes that are available in the application’s service container. Laravel ships with many facades which provide access to almost all of Laravel’s features.
在 Laravel 文档中,您会看到许多与 Laravel 功能交互的代码示例使用了“门面”。门面为在应用程序的服务容器中可用的类提供了一个“静态”接口。Laravel 提供了许多门面,这些门面提供了几乎所有 Laravel 功能的访问。
Laravel facades serve as “static proxies” to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods. It’s perfectly fine if you don’t totally understand how facades work - just go with the flow and continue learning about Laravel.
Laravel 门面充当服务容器中底层类的“静态代理”,提供了简洁、表达力强的语法,同时保持了比传统静态方法更好的可测试性和灵活性。如果您不完全理解门面是如何工作的也没有关系 - 只需随波逐流,继续学习有关 Laravel 的知识。
All of Laravel’s facades are defined in the Illuminate\Support\Facades namespace. So, we can easily access a facade like so:
所有 Laravel 的门面都被定义在
Illuminate\Support\Facades命名空间中。因此,我们可以轻松访问门面:
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;
Route::get('/cache', function () {
return Cache::get('key');
});
Throughout the Laravel documentation, many of the examples will use facades to demonstrate various features of the framework.
在 Laravel 文档中,许多示例将使用门面来展示框架的各种功能。
Helper Functions
To complement facades, Laravel offers a variety of global “helper functions” that make it even easier to interact with common Laravel features. Some of the common helper functions you may interact with are view, response, url, config, and more. Each helper function offered by Laravel is documented with their corresponding feature; however, a complete list is available within the dedicated helper documentation.
为了补充门面,Laravel 提供了各种全局“辅助函数”,使与常见 Laravel 功能进行交互变得更加容易。您可能会与一些常见的辅助函数进行交互,例如
view、response、url、config等等。Laravel 提供的每个辅助函数都有其相应功能的文档; 但是,完整的列表可以在专门的辅助函数文档中找到。
For example, instead of using the Illuminate\Support\Facades\Response facade to generate a JSON response, we may simply use the response function. Because helper functions are globally available, you do not need to import any classes in order to use them:
例如,我们可以使用
response函数而不是使用Illuminate\Support\Facades\Response门面来生成 JSON 响应。由于辅助函数是全局可用的,因此您无需导入任何类即可使用它们:
use Illuminate\Support\Facades\Response;
Route::get('/users', function () {
return Response::json([
// ...
]);
});
Route::get('/users', function () {
return response()->json([
// ...
]);
});
When to Utilize Facades
Facades have many benefits. They provide a terse, memorable syntax that allows you to use Laravel’s features without remembering long class names that must be injected or configured manually. Furthermore, because of their unique usage of PHP’s dynamic methods, they are easy to test.
门面有许多优势。它们提供了简洁、易记的语法,使您能够使用 Laravel 的功能,而无需记住必须手动注入或配置的冗长类名。此外,由于它们独特地使用了 PHP 的动态方法,因此很容易进行测试。
However, some care must be taken when using facades. The primary danger of facades is class “scope creep”. Since facades are so easy to use and do not require injection, it can be easy to let your classes continue to grow and use many facades in a single class. Using dependency injection, this potential is mitigated by the visual feedback a large constructor gives you that your class is growing too large. So, when using facades, pay special attention to the size of your class so that its scope of responsibility stays narrow. If your class is getting too large, consider splitting it into multiple smaller classes.
然而,在使用门面时需要注意一些事项。门面的主要危险是类“范围扩散”。由于门面使用起来非常简单,而且不需要注入,因此很容易让您的类继续增长,并在单个类中使用许多门面。使用依赖注入,通过大型构造函数带给您的视觉反馈,可以缓解这种潜在问题,让您意识到您的类正在变得过大。因此,在使用门面时,特别注意您的类的大小,确保其责任范围保持狭窄。如果您的类变得过大,请考虑将其拆分为多个较小的类。
Facades vs. Dependency Injection
One of the primary benefits of dependency injection is the ability to swap implementations of the injected class. This is useful during testing since you can inject a mock or stub and assert that various methods were called on the stub.
依赖注入的主要好处之一是能够替换被注入类的实现。这在测试过程中非常有用,因为您可以注入一个模拟或存根,并断言存根上调用了各种方法。
Typically, it would not be possible to mock or stub a truly static class method. However, since facades use dynamic methods to proxy method calls to objects resolved from the service container, we actually can test facades just as we would test an injected class instance. For example, given the following route:
通常情况下,对一个真正的静态类方法进行模拟或存根化是不可能的。然而,由于门面使用动态方法将方法调用代理到从服务容器中解析的对象上,实际上我们可以像测试注入的类实例一样测试门面。例如,给定以下路由:
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});
Using Laravel’s facade testing methods, we can write the following test to verify that the Cache::get method was called with the argument we expected:
使用 Laravel 的门面测试方法,我们可以编写以下测试来验证我们所期望的参数被传递给了Cache::get方法:
PestPHPUnit
use Illuminate\Support\Facades\Cache;
test('basic example', function () {
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$response = $this->get('/cache');
$response->assertSee('value');
});
Facades vs. Helper Functions
In addition to facades, Laravel includes a variety of “helper” functions which can perform common tasks like generating views, firing events, dispatching jobs, or sending HTTP responses. Many of these helper functions perform the same function as a corresponding facade. For example, this facade call and helper call are equivalent:
除了门面之外,Laravel 还包括各种“辅助”函数,可以执行诸如生成视图、触发事件、调度作业或发送 HTTP 响应等常见任务。许多这些辅助函数执行的功能与相应的门面类似。例如,下面的门面调用和辅助函数调用是等效的:
return Illuminate\Support\Facades\View::make('profile');
return view('profile');
There is absolutely no practical difference between facades and helper functions. When using helper functions, you may still test them exactly as you would the corresponding facade. For example, given the following route:
在实际上,门面和辅助函数之间没有任何实质性区别。当使用辅助函数时,您仍然可以像测试相应的门面一样来测试它们。例如,考虑以下路由:
Route::get('/cache', function () {
return cache('key');
});
The cache helper is going to call the get method on the class underlying the Cache facade. So, even though we are using the helper function, we can write the following test to verify that the method was called with the argument we expected:
cache辅助函数将调用支持Cache门面的类的get方法。因此,即使我们使用辅助函数,我们仍然可以编写以下测试来验证该方法是否按我们期望的方式被调用了:
use Illuminate\Support\Facades\Cache;
/**
* A basic functional test example.
*/
public function test_basic_example(): void
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$response = $this->get('/cache');
$response->assertSee('value');
}
How Facades Work
In a Laravel application, a facade is a class that provides access to an object from the container. The machinery that makes this work is in the Facade class. Laravel’s facades, and any custom facades you create, will extend the base Illuminate\Support\Facades\Facade class.
在 Laravel 应用程序中,门面是一个类,它提供对容器中对象的访问。实现这一功能的机制在
Facade类中。Laravel 的门面,以及您创建的任何自定义门面,都将扩展基本的Illuminate\Support\Facades\Facade类。
The Facade base class makes use of the __callStatic() magic-method to defer calls from your facade to an object resolved from the container. In the example below, a call is made to the Laravel cache system. By glancing at this code, one might assume that the static get method is being called on the Cache class:
Facade基类利用了__callStatic()魔术方法,将您门面的调用延迟到从容器中解析的对象上。在下面的示例中,对 Laravel 缓存系统进行了调用。通过一瞥代码,人们可能会认为是在Cache类上调用静态的get方法:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*/
public function showProfile(string $id): View
{
$user = Cache::get('user:'.$id);
return view('profile', ['user' => $user]);
}
}
Notice that near the top of the file we are “importing” the Cache facade. This facade serves as a proxy for accessing the underlying implementation of the Illuminate\Contracts\Cache\Factory interface. Any calls we make using the facade will be passed to the underlying instance of Laravel’s cache service.
请注意,文件顶部我们“导入”了
Cache门面。该门面充当访问Illuminate\Contracts\Cache\Factory接口的基础实现的代理。我们使用门面进行的任何调用都将传递给 Laravel 缓存服务的基础实例。
If we look at that Illuminate\Support\Facades\Cache class, you’ll see that there is no static method get:
如果我们查看
Illuminate\Support\Facades\Cache类,你会发现并没有静态方法get:
class Cache extends Facade
{
/**
* Get the registered name of the component.
*/
protected static function getFacadeAccessor(): string
{
return 'cache';
}
}
Instead, the Cache facade extends the base Facade class and defines the method getFacadeAccessor(). This method’s job is to return the name of a service container binding. When a user references any static method on the Cache facade, Laravel resolves the cache binding from the service container and runs the requested method (in this case, get) against that object.
相反,
Cache门面继承了基础的Facade类,并定义了方法getFacadeAccessor()。该方法的作用是返回服务容器绑定的名称。当用户引用Cache门面上的任何静态方法时,Laravel会从服务容器中解析cache绑定,并针对该对象运行请求的方法(在本例中为get)。
Real-Time Facades
Using real-time facades, you may treat any class in your application as if it was a facade. To illustrate how this can be used, let’s first examine some code that does not use real-time facades. For example, let’s assume our Podcast model has a publish method. However, in order to publish the podcast, we need to inject a Publisher instance:
使用实时门面,你可以将应用程序中的任何类都视为门面来使用。为了说明如何使用实时门面,让我们先检查一些不使用实时门面的代码。例如,假设我们的
Podcast模型有一个publish方法。然而,为了发布播客,我们需要注入一个Publisher实例:
<?php
namespace App\Models;
use App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;
class Podcast extends Model
{
/**
* Publish the podcast.
*/
public function publish(Publisher $publisher): void
{
$this->update(['publishing' => now()]);
$publisher->publish($this);
}
}
Injecting a publisher implementation into the method allows us to easily test the method in isolation since we can mock the injected publisher. However, it requires us to always pass a publisher instance each time we call the publish method. Using real-time facades, we can maintain the same testability while not being required to explicitly pass a Publisher instance. To generate a real-time facade, prefix the namespace of the imported class with Facades:
将出版商实现注入方法允许我们轻松地对方法进行隔离测试,因为我们可以对注入的出版商进行模拟。然而,这要求我们每次调用
publish方法时都必须传递一个出版商实例。通过使用实时门面,我们可以保持相同的可测试性,而无需显式传递Publisher实例。要生成一个实时门面,将导入类的命名空间前缀设置为Facades:
<?php
namespace App\Models;
use App\Contracts\Publisher;
use Facades\App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;
class Podcast extends Model
{
/**
* Publish the podcast.
*/
public function publish(Publisher $publisher): void
public function publish(): void
{
$this->update(['publishing' => now()]);
$publisher->publish($this);
Publisher::publish($this);
}
}
When the real-time facade is used, the publisher implementation will be resolved out of the service container using the portion of the interface or class name that appears after the Facades prefix. When testing, we can use Laravel’s built-in facade testing helpers to mock this method call:
使用实时门面时,出版商实现将通过使用出现在
Facades前缀之后的接口或类名的部分在服务容器中解析。在测试时,我们可以使用 Laravel 内置的门面测试助手来模拟此方法调用:
PestPHPUnit
<?php
use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
test('podcast can be published', function () {
$podcast = Podcast::factory()->create();
Publisher::shouldReceive('publish')->once()->with($podcast);
$podcast->publish();
});
Facade Class Reference
Below you will find every facade and its underlying class. This is a useful tool for quickly digging into the API documentation for a given facade root. The service container binding key is also included where applicable.
以下是每个门面及其对应的基础类。这是一个快速查阅给定门面根的 API 文档的有用工具。如果适用,还包括了 服务容器绑定 的键。
本文详细介绍了Laravel中的门面(Facades)概念,包括其与依赖注入、辅助函数的关系,以及如何利用它们进行简洁编程和测试。还探讨了何时使用门面以及与静态方法和辅助函数的比较。

1408

被折叠的 条评论
为什么被折叠?



