Laravel 的合同(Contracts)就是在框架里定义核心服务的一些接口。比如,一个 Queue 合同定义了队列工作需要用到的一些方法,Mailer 合同里边定义了发送邮件要用的一些方法。
框架为每个合同都提供了一个对应的实施。比如,Laravel 提供了一个 Queue 实施,里面有各种驱动,Mailer 实施里面用的是 SwiftMailer 。
所有的 Laravel 合同都在各种的 Github 仓库里。这为所有可用的合同,都提供了一个可以快速查看参考的地方,这样其它的开发者可以使用这些独立的,解耦的包。
为什么要用合同
你可能会有些疑问,为什么要用合同,使用接口干啥,这不是更复杂吗?下面介绍两个主要的原因,松耦合与简洁。
松耦合
先来看点实施缓存的紧耦合的代码:
<?php namespace App\Orders;
class Repository {
/**
* The cache.
*/
protected $cache;
/**
* Create a new repository instance.
*
* @param \Package\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 {
/**
* Create a new repository instance.
*
* @param Cache $cache
* @return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}现在,代码不再跟一个特定的 vendor 绑定到一块儿了,甚至跟 Laravel 也一样。合同包里不包含实施也没有依赖,你可以简单的为任何合同去写一个替代的实施,这样你可以在不通知任何使用缓存的代码的情况下,替换掉你的缓存实施。
简洁
所有 Laravel 的服务都是用的简单的接口定义的,这样就很容易确定哪些功能来自哪些服务。合同的作用就是为架构的功能提供一个简洁的文档。别把方法放到一个巨大又复杂的类里面,使用简单,整洁的接口。这样你的代码就会很容易明白与维护。
合同参考
下面是 Laravel 里的大部分合同,还有跟它们对应的 facade。
如何创建合同
怎么样去实施合同?在 Laravel 里面的大部分类都是通过 Service Container 去 resolved ,包括控制器,事件监听器,过滤器,队列工作,甚至 Closures 路由。要去实施一个合同,你只需要在要 resolved 类的构造函数里面去 type-hint 接口。比如,看一下,下面这个 event handler :
<?php namespace App\Handlers\Events;
use App\User;
use App\Events\NewUserRegistered;
use Illuminate\Contracts\Redis\Database;
class CacheUserInformation {
/**
* 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 NewUserRegistered $event
* @return void
*/
public function handle(NewUserRegistered $event)
{
//
}
}当事件监听器被 resolved 以后,Service Container 会去读取在类的构造函数上的 type-hint ,然后会注入适当的值。了解怎么样在 Service Container 上注册东西,可以查看这个文档。
Laravel Laravel5 中文手册


