Facades
介绍
Facades 为应用程序的服务容器中可用的类提供了一个“静态”接口。Laravel 附带了许多 facades,您可能在不知不觉中已经在使用它们!Laravel 的“facades”作为服务容器中底层类的“静态代理”,提供了简洁、富有表现力的语法,同时比传统的静态方法具有更好的可测试性和灵活性。
有时,您可能希望为应用程序和包创建自己的 facades,因此让我们来探索这些类的概念、开发和使用。
在深入了解 facades 之前,强烈建议您非常熟悉 Laravel 的服务容器。
解释
在 Laravel 应用程序的上下文中,facade 是一个提供对容器中对象访问的类。使这项工作成为可能的机制在 Facade
类中。Laravel 的 facades 以及您创建的任何自定义 facades 都将扩展基础 Facade
类。
您的 facade 类只需要实现一个方法:getFacadeAccessor
。getFacadeAccessor
方法的任务是定义从容器中解析什么。Facade
基类利用 __callStatic()
魔术方法将来自您的 facade 的调用推迟到已解析的对象。
因此,当您进行类似 Cache::get
的 facade 调用时,Laravel 会从服务容器中解析 Cache 管理器类,并在该类上调用 get
方法。从技术上讲,Laravel Facades 是使用 Laravel 服务容器作为服务定位器的便捷语法。
实际使用
在下面的示例中,调用了 Laravel 缓存系统。通过浏览此代码,您可能会认为静态方法 get
正在被调用在 Cache
类上。
$value = Cache::get('key');
然而,如果我们查看 Illuminate\Support\Facades\Cache
类,您会发现没有静态方法 get
:
class Cache extends Facade {
/**
* 获取组件的注册名称。
*
* @return string
*/
protected static function getFacadeAccessor() { return 'cache'; }
}
Cache 类扩展了基础 Facade
类并定义了一个方法 getFacadeAccessor()
。请记住,此方法的任务是返回服务容器绑定的名称。
当用户引用 Cache
facade 上的任何静态方法时,Laravel 会从服务容器中解析 cache
绑定,并在该对象上运行请求的方法(在本例中为 get
)。
因此,我们的 Cache::get
调用可以重写为:
$value = $app->make('cache')->get('key');
导入 Facades
请记住,如果您在命名空间的控制器中使用 facade,您需要将 facade 类导入到命名空间中。所有 facades 都位于全局命名空间中:
<?php namespace App\Http\Controllers;
use Cache;
class PhotosController extends Controller {
/**
* 获取所有应用程序照片。
*
* @return Response
*/
public function index()
{
$photos = Cache::get('photos');
//
}
}
创建 Facades
为您自己的应用程序或包创建 facade 很简单。您只需要 3 件事:
- 一个服务容器绑定。
- 一个 facade 类。
- 一个 facade 别名配置。
让我们看一个例子。这里,我们定义了一个类 PaymentGateway\Payment
。
namespace PaymentGateway;
class Payment {
public function process()
{
//
}
}
我们需要能够从服务容器中解析此类。因此,让我们将绑定添加到服务提供者中:
App::bind('payment', function()
{
return new \PaymentGateway\Payment;
});
注册此绑定的一个好地方是创建一个名为 PaymentServiceProvider
的新服务提供者,并将此绑定添加到 register
方法中。然后,您可以配置 Laravel 从 config/app.php
配置文件加载您的服务提供者。
接下来,我们可以创建我们自己的 facade 类:
use Illuminate\Support\Facades\Facade;
class Payment extends Facade {
protected static function getFacadeAccessor() { return 'payment'; }
}
最后,如果我们愿意,我们可以将我们的 facade 的别名添加到 config/app.php
配置文件中的 aliases
数组中。现在,我们可以在 Payment
类的实例上调用 process
方法。
Payment::process();
关于自动加载别名的说明
在某些情况下,aliases
数组中的类不可用,因为 PHP 不会尝试自动加载未定义的类型提示类。如果 \ServiceWrapper\ApiTimeoutException
被别名为 ApiTimeoutException
,则在命名空间 \ServiceWrapper
之外的 catch(ApiTimeoutException $e)
永远不会捕获异常,即使抛出了一个异常。在具有类型提示到别名类的类中也会发现类似的问题。唯一的解决方法是放弃别名,并在每个需要它们的文件顶部 use
您希望类型提示的类。
模拟 Facades
单元测试是 facades 之所以如此工作的一个重要方面。事实上,可测试性是 facades 存在的主要原因。有关更多信息,请查看文档的模拟 facades部分。
Facade 类参考
下面您将找到每个 facade 及其底层类。这是快速深入了解给定 facade 根的 API 文档的有用工具。还包括适用的服务容器绑定键。