Skip to content

Laravel - Facade

外观(Facades)为应用服务容器中可用的类提供了一个“静态”接口。Laravel 的外观充当了服务容器中底层类的“静态代理”,提供了简洁、富有表达力的语法,同时比传统的静态方法具有更好的可测试性和灵活性。

所有 Laravel 的外观都定义在 Illuminate\Support\Facades 命名空间下。因此,我们可以很容易地像这样访问一个外观:

use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});

在 Laravel 文档中,许多示例都会使用外观来演示框架的各种功能。

外观有很多好处。它们提供了简洁、易记的语法,让你无需记住那些必须手动注入或配置的长类名就可以使用 Laravel 的功能。此外,由于它们独特地使用了 PHP 的动态方法,它们很容易进行测试。

然而,使用外观时必须小心。外观的主要风险是类范围蔓延(class scope creep)。由于外观非常易于使用且不需要注入,很容易让你的类变得过于庞大,并在一个类中使用许多外观。当使用依赖注入时,通过大型构造函数带来的视觉反馈可以减轻类变得过大的可能性。因此,使用外观时,请特别注意类的规模,以保持其职责范围狭窄。

在构建与 Laravel 交互的第三方包时,通常最好注入 Laravel 的契约(contracts)而不是使用外观。由于包是在 Laravel 本身之外构建的,你将无法访问 Laravel 的外观测试辅助功能。

在 Laravel 应用中,外观是一个类,它提供了从容器中访问对象的能力。实现此功能的核心在于 Facade 类。Laravel 的外观以及你创建的任何自定义外观都将继承基础的 Illuminate\Support\Facades\Facade 类。

基础 Facade 类利用了 __callStatic() 魔术方法来将对外观的调用延迟到从容器解析出的对象。在下面的示例中,调用了 Laravel 的缓存系统。乍一看这段代码,人们可能会认为静态方法 get 是在 Cache 类上调用的:

<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
public function index()
{
$value = Cache::get('key');
// ...
}
}

请注意,在文件顶部我们“导入”了 Cache 外观。这个外观充当了访问底层 Illuminate\Contracts\Cache\Factory 接口实现的代理。我们通过外观进行的任何调用都将传递给 Laravel 缓存服务的底层实例。

如果你查看 Illuminate\Support\Facades\Cache 类,你会发现并没有静态方法 get:

class Cache extends Facade
{
protected static function getFacadeAccessor()
{
return 'cache';
}
}

相反,Cache 外观继承了基础 Facade 类并定义了 getFacadeAccessor() 方法。该方法的作用是返回服务容器绑定的名称。当用户引用 Cache 外观上的任何静态方法时,Laravel 会从服务容器中解析出 cache 绑定,并对该对象运行请求的方法(在本例中是 get)。

为自己的应用或包创建外观非常简单。你只需要三样东西:

  • 一个服务容器绑定。
  • 一个外观类。
  • 一个外观别名配置(可选,但常用)。

示例:创建一个自定义支付网关外观

Section titled “示例:创建一个自定义支付网关外观”

步骤 1:创建服务类。这是将执行实际工作的类。

创建文件 app/Services/PaymentGateway.php:

app/Services/PaymentGateway.php

<?php
namespace App\Services;
class PaymentGateway
{
public function processPayment(float $amount)
{
// 在实际应用中,这里会与支付 API 交互
return "Processing payment of $" . number_format($amount, 2);
}
}

步骤 2:创建一个服务提供者(Service Provider)将你的类绑定到服务容器。

在你的终端中运行 php artisan make:provider PaymentServiceProvider 命令。该命令将在 app/Providers/PaymentServiceProvider.php 中创建一个新的提供者。编辑此文件:

app/Providers/PaymentServiceProvider.php

<?php
namespace App\Providers;
use App\Services\PaymentGateway;
use Illuminate\Support\ServiceProvider;
class PaymentServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->bind('payment.gateway', function ($app) {
return new PaymentGateway();
});
}
public function boot(): void
{
//
}
}

步骤 3:注册服务提供者。将你的 PaymentServiceProvider 添加到 config/app.php 配置文件中的 providers 数组:

config/app.php (providers 数组片段)

'providers' => ServiceProvider::defaultProviders()->merge([
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\PaymentServiceProvider::class, // Add this line
])->toArray(),

步骤 4:创建外观类。此类应继承 Illuminate\Support\Facades\Facade 并实现 getFacadeAccessor 方法。此方法应返回你在服务提供者中使用的服务容器绑定键 (payment.gateway)。

创建文件 app/Facades/Payment.php:

app/Facades/Payment.php

<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Payment extends Facade
{
protected static function getFacadeAccessor(): string
{
return 'payment.gateway';
}
}

步骤 5:(可选) 添加外观别名。如果你想在不通过完整命名空间导入的情况下使用你的外观,可以将别名添加到 config/app.php 配置文件的 aliases 数组中。

config/app.php (aliases 数组片段)

'aliases' => Facade::defaultAliases()->merge([
'Payment' => App\Facades\Payment::class,
])->toArray(),

步骤 6:使用你的新外观。你现在可以在应用中使用你的外观了,例如在路由或控制器中。

routes/web.php

use App\Facades\Payment; // Or use the alias 'Payment' if configured
Route::get('/pay', function(){
return Payment::processPayment(19.99);
});

步骤 7:测试它。在浏览器中访问 http://localhost:8000/pay。你应该会看到输出:“Processing payment of $19.99”。

下面是每个外观及其底层类的列表。这是一个有用的工具,可以快速查阅给定外观根的 API 文档。如果适用,还包括了服务容器绑定键。

外观(Facade)类(Class)服务容器绑定(Service Container Binding)
FacadeClassService Container Binding
AppIlluminate\Foundation\Applicationapp
ArtisanIlluminate\Contracts\Console\Kernelartisan
AuthIlluminate\Auth\AuthManagerauth
Auth (Instance)Illuminate\Contracts\Auth\Guard
BladeIlluminate\View\Compilers\BladeCompilerblade.compiler
BroadcastIlluminate\Contracts\Broadcasting\Factorybroadcast
BusIlluminate\Contracts\Bus\Dispatcherbus
CacheIlluminate\Cache\CacheManagercache
Cache (Instance)Illuminate\Contracts\Cache\Repository
ConfigIlluminate\Config\Repositoryconfig
CookieIlluminate\Cookie\CookieJarcookie
CryptIlluminate\Encryption\Encrypterencrypter
DBIlluminate\Database\DatabaseManagerdb
DB (Instance)Illuminate\Database\Connection
EventIlluminate\Events\Dispatcherevents
FileIlluminate\Filesystem\Filesystemfiles
GateIlluminate\Contracts\Auth\Access\Gategate
HashIlluminate\Contracts\Hashing\Hasherhash
HttpIlluminate\Support\Facades\Httphttp
LangIlluminate\Translation\Translatortranslator
LogIlluminate\Log\LogManagerlog
MailIlluminate\Mail\Mailermailer
NotificationIlluminate\Notifications\ChannelManagernotification
PasswordIlluminate\Auth\Passwords\PasswordBrokerManagerauth.password
Password (Instance)Illuminate\Auth\Passwords\PasswordBroker
QueueIlluminate\Queue\QueueManagerqueue
Queue (Instance)Illuminate\Contracts\Queue\Queue
RateLimiterIlluminate\Cache\RateLimiterlimiter
RedirectIlluminate\Routing\Redirectorredirect
RedisIlluminate\Redis\RedisManagerredis
Redis (Instance)Illuminate\Contracts\Redis\Connection
RequestIlluminate\Http\Requestrequest
ResponseIlluminate\Contracts\Routing\ResponseFactoryresponse
RouteIlluminate\Routing\Routerrouter
SchemaIlluminate\Database\Schema\Builderdb.schema
SessionIlluminate\Session\SessionManagersession
Session (Instance)Illuminate\Session\Store
StorageIlluminate\Filesystem\FilesystemManagerfilesystem
Storage (Instance)Illuminate\Contracts\Filesystem\Filesystem
URLIlluminate\Routing\UrlGeneratorurl
ValidatorIlluminate\Validation\Factoryvalidator
Validator (Instance)Illuminate\Contracts\Validation\Validator
ViewIlluminate\View\Factoryview
View (Instance)Illuminate\Contracts\View\View
ViteIlluminate\Foundation\Vite

注意:上述列表是代表性的,可能并非涵盖所有或与最新 Laravel 版本完全同步,但它包含了最常用的外观。始终参考官方 Laravel API 文档以获取最新信息。