简介
Laravel 的 Contracts 是由框架提供的、定义了核心服务的一组接口。例如 Illuminate\Contracts\Queue\Queue
contract 定义了队列任务需要的方法。而 Illuminate\Contracts\Mail\Mailer
定义了发送邮件需要的方法。
框架中每个 contract 都有相应的实现。例如,Laravel 提供了多种驱动实现队列,以及 SwiftMailer 驱动的邮件服务的实现。
Laravel 所有的 contracts 都放在他们的 Github 代码仓库中。这为查看所有 contracts 提供了一个快速参考,降低耦合来让其他扩展包开发者使用。
Contracts Vs. Facades
Laravel 的 facades 及其辅助函数提供了一个简单的方法来使用 Laravel 的服务,不需要在服务容器之外使用类型提示以及获取 contracts。大多数情况下,每一个 facade 都有一个相应的 contract。
使用 facades,你不需要在类的构造函数中引入它们,而使用 contracts,则需要你在类中明确定义一个依赖。有些开发者更喜欢使用这种方式明确的在类中定义依赖,因而喜欢这种方法,而另一些则喜欢 facades 的便捷性。
何时使用 Contracts
正如其他地方讨论的那样,使用 facades 还是 contracts 最终取决于你的个人喜好已经开发团队的需要。ContractsC 及 facades 都可以创建强大的、易于测试的应用。只要你的类责任明确,你会注意到 facades 和 contracts 中间并没有什么明显的区别。
然而,对于 contracts 你可能还有其他的一些问题。例如,为什么要使用接口?使用接口不是更复杂吗?让我们用下面的标题来解释为什么要使用接口:低耦合和简单性。
低耦合
首先,让我们来查看这一段和缓存功能有高耦合的代码,如下:
<?php namespace App\Orders; class Repository { /** * The cache instance. */ protected $cache; /** * Create a new repository instance. * * @param \SomePackage\Cache\Memcached $cache * @return void */ public function __construct(\SomePackage\Cache\Memcached $cache) { $this->cache = $cache; } /** * Retrieve an Order by ID. * * @param int $id * @return Order */ public function find($id) { if ($this->cache->has($id)) { // } } }
在这个类中,代码与给定的缓存实现是高耦合的。说其是高耦合的,是因为依赖扩展包中指定的一个缓存类,如果这个包的 API 变了,我们的代码也要修改。
同样的,如果我们想把底层的缓存技术(Memcached)替换为其他技术(Redis),我们也必须更新代码库。我们的代码块不在意是谁在为它提供数据或如何提供数据。
作为一种替换方式,我们可以使用一个简单的接口:
<?php namespace App\Orders; use Illuminate\Contracts\Cache\Repository as Cache; class Repository { /** * The cache instance. */ protected $cache; /** * Create a new repository instance. * * @param Cache $cache * @return void */ public function __construct(Cache $cache) { $this->cache = $cache; } }
现在上面的代码没有跟任何扩展包耦合,甚至是 Laravel。由于 contracts 不包含任何实现和依赖,你可以轻松为任何给定的 contract 编写替代实现,允许你不修改任何缓存使用处的代码就可以替换缓存实现。
简单
当所有的 Laravel 服务都使用简洁的接口定义,就能够很容易决定一个服务需要提供的功能。 可以将 contracts 视为说明框架特色的简洁文档。
此外,但你依赖简单接口的时候,你的代码就更容易理解和维护。比起搜索一个大型复杂的类里有哪些可用的方法,你有一个简单,干净的接口可以参考。
如何使用 Contracts
那么,你如何获取一个 contract 的实现?这真的非常简单。
Laravel 中很多类型的类都是通过服务容器解析的,包括控制器、事件监听器、中间件、队列任务、甚至是路由。所以,要获取一个 contract 的实现,你可以在构造函数中为要获取的类的接口做类型提示。
例如,看下面的事件监听器:
<?php namespace App\Listeners; use App\User; use App\Events\OrderWasPlaced; use Illuminate\Contracts\Redis\Database; class CacheOrderInformation { /** * The Redis database implementation. */ protected $redis; /** * Create a new event handler instance. * * @param Database $redis * @return void */ public function __construct(Database $redis) { $this->redis = $redis; } /** * Handle the event. * * @param OrderWasPlaced $event * @return void */ public function handle(OrderWasPlaced $event) { // } }
当获取到事件监听器后,服务容器将会在类的构造函数中读取类型提示,并注入一个合适的值。要查看关于在服务容器中注册事物的更多内容,请查看其文档。
Contract 参考
下表提供了 Laravel 所有的 contracts 及其对应的 facades:
该篇属于专题:《Laravel 5.3 中文文档》