首页 » Laravel 5.3 中文文档 » 正文

「Laravel 5.3 中文文档」核心概念 – Facades

简介

Facade 为应用的服务容器中可访问的方法提供了一个“静态”的接口。Laravel 提供了多个 facades,它们几乎可以访问 Laravel 的所有功能。Laravel facades 作为服务容器底层类的“静态代理”,提供了简洁、生动的语法,并且比传统的静态方法更加易测试、更加灵活。

Laravel 所有的 facades 都定义在 Illuminate\Support\Facades 命名空间下。所以你可以像这样轻松的访问一个 facade:

use Illuminate\Support\Facades\Cache;

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

浏览文档的工程中,你会看到很多例子都会使用 facade 来演示 Laravel 的多种功能。

何时使用 Facade

Facades 有很多好处。它们提供了简洁、令人难忘的语法,允许你在不用记住那些必须注入或手动配置的很长的类名的情况下使用 Laravel 的功能。并且,由于它们对 PHP 动态方法的独特的使用方式,使得它们很容易进行测试。

然后,在使用 Facades 时有些事情必须注意。Facades 的主要危害是类的范围衍生。由于 Facades 很容易使用且不需要注入,这很容易使你的类持续变大并在一个类中使用多个 Facades。使用依赖注入的话,视觉上的感受会使这种潜在的问题得到一些缓解,因为一个大的构造函数提示着你你的类正在变大。所以,使用 Facades 时,要特别注意类的大小,使它尽量的小。

在创建一个与 Laravel 交互的第三方类库的时候,最好是使用 Laravel contracts 而非 Facades。由于 Facades 是创建在 Laravel 之外的,你将不能访问 Laravel 的 facade 辅助函数。

Facades Vs. 依赖注入

依赖注入其中一个主要优点是替换注入类的实现的能力。这在测试的时候是非常有用的,因为你可以注入一个模拟或存根,并断言各种方法都通过存根调用。

通常情况下是不能模拟或存根一个真实的静态方法的。然而,由于 Facades 使用动态方式代理从服务容器获取的对象的方法调用,事实上我们可以像测试注入类的实例那样测试 facades。例如,给定下面的路由:

use Illuminate\Support\Facades\Cache;

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

我们可以通过下面的测试来核实 Cache::get 方法是通过我们期望的那样调用参数:

use Illuminate\Support\Facades\Cache;

/**
 * A basic functional test example.
 *
 * @return void
 */
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

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

Facades Vs. 辅助函数

除了 Facades,Laravel 还提供了多种“辅助”方法来执行诸如生成视图、触发事件、调度任务或发送 HTTP 请求等常见的任务。其中许多辅助方法都与相应的 facade 执行相同的功能。例如,下面的 facade 调用和辅助方法调用是相等的:

return View::make('profile');

return view('profile');

Facades 与辅助方法其实并没有什么实质的区别。当使用辅助方法时,你可以像测试相应的 facade 那样测它们。例如,给定下面的路由:

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

在内部,cache 辅助函数将会调用位于 Cache facade 内的 get 方法。所以,即使我们使用辅助方法,我们可以通过下面的测试来核实这个方法是通过我们期望的那样调用参数:

use Illuminate\Support\Facades\Cache;

/**
 * A basic functional test example.
 *
 * @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() 魔术方法延迟调用一个从服务容器获取的对象。在下面的例子中,是对 Laravel 缓存系统的一个调用。浏览下面的代码,也许有人会认为 get 静态方法是调用自 Cache 类:

<?php

namespace App\Http\Controllers;

use Cache;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @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 方法:

class Cache extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }
}

相反,Cache 继承自 Facade 基类,并定义了 getFacadeAccessor() 方法。这个方法的作用是返回服务容器绑定的名称。当用户调用任何 Cache 类的静态方法时,Laravel 会从服务容器获取 cache 绑定,并运行请求的方法(在这个例子中为 get)而非那个对象。

Facades 类参考

下面你会看到每一个 facade 以及底层的类。这个工具对于一个给定 facade 快速查看其文档是非常有用的。服务容器绑定的键也会包含在里面:

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 (Instance)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
PasswordIlluminate\Auth\Passwords\PasswordBrokerauth.password
QueueIlluminate\Queue\QueueManagerqueue
Queue (Instance)Illuminate\Contracts\Queue\Queuequeue
Queue (Base Class)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 (Instance)Illuminate\Session\Store
StorageIlluminate\Contracts\Filesystem\Factoryfilesystem
URLIlluminate\Routing\UrlGeneratorurl
ValidatorIlluminate\Validation\Factoryvalidator
Validator (Instance)Illuminate\Validation\Validator
ViewIlluminate\View\Factoryview
View (Instance)Illuminate\View\View

该篇属于专题:《Laravel 5.3 中文文档

本文共 3 个回复

  • 匹诺曹 2016/08/23 17:10

    博主,使用您的主题时,写文章的时候好像不能类似word一样那样排版,但是看你这里又好像可以,有点懵逼了,我想要的也仅仅是更改字体大小颜色等,现在我只能通过添加样式来控制,希望博主能够解答我的疑惑,谢谢!

    • Specs 2016/08/24 00:04

      @ 匹诺曹 写文章那里,有个“可视化”和“文本”,切换到“可视化”就有菜单了

      • 匹诺曹 2016/08/24 15:41

        @ Specs 我晕哦,有个隐藏按钮,谢谢博主啦!

发表评论