Facades
Laravel 的 Facades 介绍#
简介#
Facades(读音:/fəˈsäd/ )为应用程序的 服务容器 中可用的类提供了一个「静态」接口。Laravel 自带了很多 facades ,几乎可以用来访问到 Laravel 中所有的服务。Laravel facades 实际上是服务容器中那些底层类的「静态代理」,相比于传统的静态方法, facades 在提供了简洁且丰富的语法同时,还带来了更好的可测试性和扩展性。
所有的 Laravel facades 都需要定义在命名空间 Illuminate\Support\Facades
下。所以,我们可以容易地向下面这样调用 facade :
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});
在 Laravel 的文档中,很多示例代码都是使用 facades 来演示框架的各种特性的。
何时使用 Facades#
Facades 有很多好处,它为我们使用 Laravel 的各种功能提供了简单,易记的语法,让你不需要记住长长的类名来实现依赖注入和手动配置。还有,因为它们对于 PHP 动态方法的独特用法,测试起来非常容易。
然而,在使用 facades 时,有些地方还需要特别注意。使用 facades 最主要的风险就是会引起类作用范围的膨胀。因为 facades 使用起来非常简单而且不需要注入,我们会不经意的在单个类中大量使用。它不会像使用依赖注入那样,使用的类越多,构造方法会越长,在视觉上就会引起注意,提醒你这个类有点庞大了。所以在使用 facades 的时候,要特别注意控制好类的大小,让类的作用范围保持短小。
{tip} 在开发与 Laravel 交互的第三方扩展包时,最好是在包中通过注入 Laravel contracts ,而不是在包中通过 facades 来使用 Laravel 的类。因为扩展包不是在 Laravel 内部使用的,无法使用 Laravel's facade 的测试辅助函数。
Facades Vs. 依赖注入#
依赖注入的一个主要的好处是可以切换注入类的具体实现。这在测试的时候很有用,因为你可以注入一个 mock 或者 stub ,并且对在 stub 中被调用的各种方法进行断言。
通常,静态方法是不可以被 mock 或者 stub 。但是,因为 facades 调用的是对象的动态方法,我们可以像测试注入类的实例一样测试 facades ,例如,像下面的路由:
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});
我们可以用下面的测试代码去验证 Cache::get
方法是否被调用,当传入预期的参数时。
use Illuminate\Support\Facades\Cache;
/**
* 一个基础功能的测试用例。
*
* @return void
*/
public function testBasicExample()
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$this->visit('/cache')
->see('value');
}
Facades Vs. 辅助函数#
除了 facades , Laravel 包含一些「辅助函数」来实现一些常用的功能,比如生成视图,触发事件,调度任务或者发送 HTTP 响应。许多辅助函数的功能和对应的 facades 一样。例如,下面这个 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;
/**
* 一个基础功能的测试用例。
*
* @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()
魔术方法在你的 facades 中延迟调用容器中对应对象的方法,在下面的例子中,调用了 Laravel 的缓存系统。在代码里,我们可能认为是 Cache
类中的静态方法 get
被调用了:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
use App\Http\Controllers\Controller;
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
这个静态方法:
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 类对应的可用键值。
{note} 欢迎任何形式的转载,但请务必注明出处,尊重他人劳动共创开源社区。
转载请注明:本文档由 Laravel China 社区 [laravel-china.org] 组织翻译,详见 翻译召集帖。
文档永久地址: d.laravel-china.org