Skip to content
虚位以待
赞助商
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

合同

介绍

Laravel 的合同是一组接口,定义了框架提供的核心服务。例如,Queue 合同定义了队列作业所需的方法,而 Mailer 合同定义了发送电子邮件所需的方法。

每个合同都有框架提供的相应实现。例如,Laravel 提供了具有多种驱动程序的 Queue 实现,以及由 SwiftMailer 提供支持的 Mailer 实现。

所有 Laravel 合同都位于他们自己的 GitHub 仓库中。这为所有可用合同提供了一个快速参考点,以及一个可以被其他包开发者利用的单一、解耦的包。

为什么使用合同?

您可能对合同有几个问题。为什么要使用接口?使用接口不是更复杂吗?

让我们将使用接口的原因简化为以下几个标题:松耦合和简单性。

松耦合

首先,让我们回顾一些与缓存实现紧密耦合的代码。考虑以下内容:

php
<?php namespace App\Orders;

class Repository {

	/**
	 * 缓存。
	 */
	protected $cache;

	/**
	 * 创建一个新的仓库实例。
	 *
	 * @param  \SomePackage\Cache\Memcached  $cache
	 * @return void
	 */
	public function __construct(\SomePackage\Cache\Memcached $cache)
	{
		$this->cache = $cache;
	}

	/**
	 * 通过 ID 检索订单。
	 *
	 * @param  int  $id
	 * @return Order
	 */
	public function find($id)
	{
		if ($this->cache->has($id))
		{
			//
		}
	}

}

在这个类中,代码与给定的缓存实现紧密耦合。它是紧密耦合的,因为我们依赖于来自包供应商的具体缓存类。如果该包的 API 发生变化,我们的代码也必须更改。

同样,如果我们想用另一种技术(如 Redis)替换我们的底层缓存技术(Memcached),我们又必须修改我们的仓库。我们的仓库不应该对谁提供数据或如何提供数据有太多了解。

相反,我们可以通过依赖一个简单的、与供应商无关的接口来改进我们的代码:

php
<?php namespace App\Orders;

use Illuminate\Contracts\Cache\Repository as Cache;

class Repository {

	/**
	 * 创建一个新的仓库实例。
	 *
	 * @param  Cache  $cache
	 * @return void
	 */
	public function __construct(Cache $cache)
	{
		$this->cache = $cache;
	}

}

现在,代码不再与任何特定供应商,甚至 Laravel 耦合。由于合同包不包含实现和依赖项,您可以轻松地编写任何给定合同的替代实现,从而无需修改任何使用缓存的代码即可替换缓存实现。

简单性

当 Laravel 的所有服务都在简单的接口中整齐地定义时,很容易确定给定服务提供的功能。合同作为框架功能的简洁文档。

此外,当您依赖简单的接口时,您的代码更易于理解和维护。与其在一个大型复杂的类中追踪可用的方法,不如参考一个简单、干净的接口。

合同参考

这是大多数 Laravel 合同的参考,以及它们的 Laravel "facade" 对应项:

合同Laravel 4.x Facade
Illuminate\Contracts\Auth\GuardAuth
Illuminate\Contracts\Auth\PasswordBrokerPassword
Illuminate\Contracts\Bus\DispatcherBus
Illuminate\Contracts\Cache\RepositoryCache
Illuminate\Contracts\Cache\FactoryCache::driver()
Illuminate\Contracts\Config\RepositoryConfig
Illuminate\Contracts\Container\ContainerApp
Illuminate\Contracts\Cookie\FactoryCookie
Illuminate\Contracts\Cookie\QueueingFactoryCookie::queue()
Illuminate\Contracts\Encryption\EncrypterCrypt
Illuminate\Contracts\Events\DispatcherEvent
Illuminate\Contracts\Filesystem\Cloud 
Illuminate\Contracts\Filesystem\FactoryFile
Illuminate\Contracts\Filesystem\FilesystemFile
Illuminate\Contracts\Foundation\ApplicationApp
Illuminate\Contracts\Hashing\HasherHash
Illuminate\Contracts\Logging\LogLog
Illuminate\Contracts\Mail\MailQueueMail::queue()
Illuminate\Contracts\Mail\MailerMail
Illuminate\Contracts\Queue\FactoryQueue::driver()
Illuminate\Contracts\Queue\QueueQueue
Illuminate\Contracts\Redis\DatabaseRedis
Illuminate\Contracts\Routing\RegistrarRoute
Illuminate\Contracts\Routing\ResponseFactoryResponse
Illuminate\Contracts\Routing\UrlGeneratorURL
Illuminate\Contracts\Support\Arrayable 
Illuminate\Contracts\Support\Jsonable 
Illuminate\Contracts\Support\Renderable 
Illuminate\Contracts\Validation\FactoryValidator::make()
Illuminate\Contracts\Validation\Validator 
Illuminate\Contracts\View\FactoryView::make()
Illuminate\Contracts\View\View 

如何使用合同

那么,如何获得合同的实现呢?其实很简单。Laravel 中的许多类型的类都是通过服务容器解析的,包括控制器、事件监听器、过滤器、队列作业,甚至是路由闭包。因此,要获得合同的实现,您只需在被解析类的构造函数中“类型提示”接口即可。例如,看看这个事件处理程序:

php
<?php namespace App\Handlers\Events;

use App\User;
use App\Events\NewUserRegistered;
use Illuminate\Contracts\Redis\Database;

class CacheUserInformation {

	/**
	 * Redis 数据库实现。
	 */
	protected $redis;

	/**
	 * 创建一个新的事件处理程序实例。
	 *
	 * @param  Database  $redis
	 * @return void
	 */
	public function __construct(Database $redis)
	{
		$this->redis = $redis;
	}

	/**
	 * 处理事件。
	 *
	 * @param  NewUserRegistered  $event
	 * @return void
	 */
	public function handle(NewUserRegistered $event)
	{
		//
	}

}

当事件监听器被解析时,服务容器将读取类构造函数上的类型提示,并注入适当的值。要了解有关在服务容器中注册内容的更多信息,请查看文档