Skip to content

外观模式

介绍

外观提供了一个“静态”接口来访问应用程序的 IoC 容器 中的类。Laravel 附带了许多外观,您可能在不知不觉中已经在使用它们!Laravel 的“外观”作为 IoC 容器中底层类的“静态代理”,提供了简洁、富有表现力的语法,同时比传统的静态方法具有更高的可测试性和灵活性。

有时,您可能希望为您的应用程序和包创建自己的外观,因此让我们来探索这些类的概念、开发和使用。

NOTE

在深入了解外观之前,强烈建议您非常熟悉 Laravel 的 IoC 容器

解释

在 Laravel 应用程序的上下文中,外观是一个提供对容器中对象访问的类。使这项工作成为可能的机制在 Facade 类中。Laravel 的外观以及您创建的任何自定义外观都将扩展基础 Facade 类。

您的外观类只需要实现一个方法:getFacadeAccessorgetFacadeAccessor 方法的任务是定义从容器中解析什么。Facade 基类利用 __callStatic() 魔术方法将来自外观的调用延迟到已解析的对象。

因此,当您进行类似 Cache::get 的外观调用时,Laravel 会从 IoC 容器中解析缓存管理器类,并在该类上调用 get 方法。从技术上讲,Laravel 外观是使用 Laravel IoC 容器作为服务定位器的便捷语法。

实际使用

在下面的示例中,调用了 Laravel 缓存系统。通过查看此代码,您可能会认为正在调用 Cache 类上的静态方法 get

php
$value = Cache::get('key');

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

php
class Cache extends Facade {

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

}

Cache 类扩展了基础 Facade 类并定义了一个方法 getFacadeAccessor()。请记住,此方法的任务是返回 IoC 绑定的名称。

当用户引用 Cache 外观上的任何静态方法时,Laravel 会从 IoC 容器中解析 cache 绑定,并在该对象上运行请求的方法(在本例中为 get)。

因此,我们的 Cache::get 调用可以重写为:

php
$value = $app->make('cache')->get('key');

创建外观

为您自己的应用程序或包创建外观很简单。您只需要 3 件事:

  • 一个 IoC 绑定。
  • 一个外观类。
  • 一个外观别名配置。

让我们来看一个例子。这里,我们定义了一个类 PaymentGateway\Payment

php
namespace PaymentGateway;

class Payment {

	public function process()
	{
		//
	}

}

此类可能位于您的 app/models 目录中,或 Composer 知道如何自动加载的任何其他目录中。

我们需要能够从 IoC 容器中解析此类。因此,让我们添加一个绑定:

php
App::bind('payment', function()
{
	return new \PaymentGateway\Payment;
});

注册此绑定的一个好地方是创建一个名为 PaymentServiceProvider 的新 服务提供者,并将此绑定添加到 register 方法中。然后,您可以配置 Laravel 从 app/config/app.php 配置文件加载您的服务提供者。

接下来,我们可以创建我们自己的外观类:

php
use Illuminate\Support\Facades\Facade;

class Payment extends Facade {

	protected static function getFacadeAccessor() { return 'payment'; }

}

最后,如果我们愿意,我们可以在 app/config/app.php 配置文件的 aliases 数组中为我们的外观添加一个别名。现在,我们可以在 Payment 类的实例上调用 process 方法。

php
Payment::process();

关于自动加载别名的注意事项

在某些情况下,aliases 数组中的类不可用,因为 PHP 不会尝试自动加载未定义的类型提示类。如果 \ServiceWrapper\ApiTimeoutException 被别名为 ApiTimeoutException,则在命名空间 \ServiceWrapper 之外的 catch(ApiTimeoutException $e) 永远不会捕获异常,即使抛出了一个异常。在具有类型提示到别名类的模型中也会发现类似的问题。唯一的解决方法是放弃别名,并在每个需要它们的文件顶部 use 您希望类型提示的类。

模拟外观

单元测试是外观工作方式的重要方面。事实上,可测试性是外观存在的主要原因。有关更多信息,请查看文档的 模拟外观 部分。

外观类参考

下面您将找到每个外观及其底层类。这是快速深入了解给定外观根的 API 文档的有用工具。还包括 IoC 绑定 键(如适用)。

外观IoC 绑定
AppIlluminate\Foundation\Applicationapp
ArtisanIlluminate\Console\Applicationartisan
AuthIlluminate\Auth\AuthManagerauth
Auth (实例)Illuminate\Auth\Guard
BladeIlluminate\View\Compilers\BladeCompilerblade.compiler
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
FormIlluminate\Html\FormBuilderform
HashIlluminate\Hashing\HasherInterfacehash
HTMLIlluminate\Html\HtmlBuilderhtml
InputIlluminate\Http\Requestrequest
LangIlluminate\Translation\Translatortranslator
LogIlluminate\Log\Writerlog
MailIlluminate\Mail\Mailermailer
PaginatorIlluminate\Pagination\Factorypaginator
Paginator (实例)Illuminate\Pagination\Paginator
PasswordIlluminate\Auth\Reminders\PasswordBrokerauth.reminder
QueueIlluminate\Queue\QueueManagerqueue
Queue (实例)Illuminate\Queue\QueueInterface
Queue (基类)Illuminate\Queue\Queue
RedirectIlluminate\Routing\Redirectorredirect
RedisIlluminate\Redis\Databaseredis
RequestIlluminate\Http\Requestrequest
ResponseIlluminate\Support\Facades\Response
RouteIlluminate\Routing\Routerrouter
SchemaIlluminate\Database\Schema\Blueprint
SessionIlluminate\Session\SessionManagersession
Session (实例)Illuminate\Session\Store
SSHIlluminate\Remote\RemoteManagerremote
SSH (实例)Illuminate\Remote\Connection
URLIlluminate\Routing\UrlGeneratorurl
ValidatorIlluminate\Validation\Factoryvalidator
Validator (实例)Illuminate\Validation\Validator
ViewIlluminate\View\Factoryview
View (实例)Illuminate\View\View