Skip to content

Facades

介绍

Facades 为应用程序的服务容器中可用的类提供了一个“静态”接口。Laravel 附带了许多 facades,几乎可以访问 Laravel 的所有功能。Laravel 的 facades 作为服务容器中底层类的“静态代理”,提供了简洁、富有表现力的语法,同时比传统的静态方法具有更好的可测试性和灵活性。

所有 Laravel 的 facades 都定义在 Illuminate\Support\Facades 命名空间中。因此,我们可以轻松地访问一个 facade,如下所示:

php
use Illuminate\Support\Facades\Cache;

Route::get('/cache', function () {
    return Cache::get('key');
});

在 Laravel 文档中,许多示例将使用 facades 来演示框架的各种功能。

何时使用 Facades

Facades 有许多优点。它们提供了一种简洁、易记的语法,使您可以使用 Laravel 的功能,而无需记住必须手动注入或配置的长类名。此外,由于它们独特地使用 PHP 的动态方法,它们易于测试。

然而,使用 facades 时必须小心。facades 的主要危险是类的范围蔓延。由于 facades 使用起来非常简单且不需要注入,因此很容易让您的类继续增长,并在单个类中使用许多 facades。使用依赖注入,这种潜力通过大型构造函数提供的视觉反馈得以缓解,提醒您类的增长过大。因此,在使用 facades 时,请特别注意类的大小,以确保其责任范围保持狭窄。

lightbulb

在构建与 Laravel 交互的第三方包时,最好注入 Laravel 合约 而不是使用 facades。由于包是在 Laravel 之外构建的,您将无法访问 Laravel 的 facade 测试助手。

Facades 与依赖注入

依赖注入的主要好处之一是能够交换注入类的实现。这在测试期间非常有用,因为您可以注入一个模拟或存根,并断言在存根上调用了各种方法。

通常,不可能模拟或存根真正的静态类方法。然而,由于 facades 使用动态方法将方法调用代理到从服务容器解析的对象,我们实际上可以像测试注入的类实例一样测试 facades。例如,给定以下路由:

php
use Illuminate\Support\Facades\Cache;

Route::get('/cache', function () {
    return Cache::get('key');
});

我们可以编写以下测试来验证 Cache::get 方法是否使用我们预期的参数被调用:

php
use Illuminate\Support\Facades\Cache;

/**
 * 一个基本的功能测试示例。
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $this->visit('/cache')
         ->see('value');
}

Facades 与辅助函数

除了 facades,Laravel 还包括各种“辅助”函数,可以执行常见任务,如生成视图、触发事件、调度作业或发送 HTTP 响应。许多这些辅助函数执行与相应 facade 相同的功能。例如,这个 facade 调用和辅助调用是等价的:

php
return View::make('profile');

return view('profile');

在 facades 和辅助函数之间没有实际区别。使用辅助函数时,您仍然可以像测试相应的 facade 一样测试它们。例如,给定以下路由:

php
Route::get('/cache', function () {
    return cache('key');
});

在底层,cache 辅助函数将调用 Cache facade 底层类的 get 方法。因此,即使我们使用辅助函数,我们也可以编写以下测试来验证该方法是否使用我们预期的参数被调用:

php
use Illuminate\Support\Facades\Cache;

/**
 * 一个基本的功能测试示例。
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $this->visit('/cache')
         ->see('value');
}

Facades 的工作原理

在 Laravel 应用程序中,facade 是一个类,它提供对容器中对象的访问。使这项工作成为可能的机制在 Facade 类中。Laravel 的 facades 以及您创建的任何自定义 facades 都将扩展基本的 Illuminate\Support\Facades\Facade 类。

Facade 基类利用 __callStatic() 魔术方法将来自您的 facade 的调用推迟到从容器解析的对象。在下面的示例中,调用了 Laravel 缓存系统。通过查看此代码,人们可能会认为静态方法 get 正在 Cache 类上被调用:

php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    /**
     * 显示给定用户的个人资料。
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}

请注意,在文件的顶部附近,我们正在“导入” Cache facade。这个 facade 作为访问 Illuminate\Contracts\Cache\Factory 接口底层实现的代理。我们使用 facade 进行的任何调用都将传递给 Laravel 缓存服务的底层实例。

如果我们查看 Illuminate\Support\Facades\Cache 类,您会看到没有静态方法 get

php
class Cache extends Facade
{
    /**
     * 获取组件的注册名称。
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }
}

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

Facade 类参考

下面您将找到每个 facade 及其底层类。这是快速深入了解给定 facade 根的 API 文档的有用工具。服务容器绑定键也在适用的地方包含。

Facade服务容器绑定
AppIlluminate\Foundation\Applicationapp
ArtisanIlluminate\Contracts\Console\Kernelartisan
AuthIlluminate\Auth\AuthManagerauth
BladeIlluminate\View\Compilers\BladeCompilerblade.compiler
BusIlluminate\Contracts\Bus\Dispatcher 
CacheIlluminate\Cache\Repositorycache
ConfigIlluminate\Config\Repositoryconfig
CookieIlluminate\Cookie\CookieJarcookie
CryptIlluminate\Encryption\Encrypterencrypter
DBIlluminate\Database\DatabaseManagerdb
DB (实例)Illuminate\Database\Connection 
EventIlluminate\Events\Dispatcherevents
FileIlluminate\Filesystem\Filesystemfiles
GateIlluminate\Contracts\Auth\Access\Gate 
HashIlluminate\Contracts\Hashing\Hasherhash
LangIlluminate\Translation\Translatortranslator
LogIlluminate\Log\Writerlog
MailIlluminate\Mail\Mailermailer
NotificationIlluminate\Notifications\ChannelManager 
PasswordIlluminate\Auth\Passwords\PasswordBrokerManagerauth.password
QueueIlluminate\Queue\QueueManagerqueue
Queue (实例)Illuminate\Contracts\Queue\Queuequeue
Queue (基类)Illuminate\Queue\Queue 
RedirectIlluminate\Routing\Redirectorredirect
RedisIlluminate\Redis\Databaseredis
RequestIlluminate\Http\Requestrequest
ResponseIlluminate\Contracts\Routing\ResponseFactory 
RouteIlluminate\Routing\Routerrouter
SchemaIlluminate\Database\Schema\Blueprint 
SessionIlluminate\Session\SessionManagersession
Session (实例)Illuminate\Session\Store 
StorageIlluminate\Contracts\Filesystem\Factoryfilesystem
URLIlluminate\Routing\UrlGeneratorurl
ValidatorIlluminate\Validation\Factoryvalidator
Validator (实例)Illuminate\Validation\Validator 
ViewIlluminate\View\Factoryview
View (实例)Illuminate\View\View