laravel 学习指南 第六章 第六节

  • TOC
    {:toc}

6.6 合约

6.6.1 简介

Laravel的合约是一组由框架(framework)提供的核心服务接口。

例如:

Illuminate\Contracts\Queue\Queue合约规定,列队工作需要的方法。

Illuminate\Contracts\Mail\Mailer合约规定,发送电子邮件的方法。

每个合约都有框架提供的,相应的实现方法。

例如:

Laravel提供一个列队实现方法与各种驱动,和一个由SwiftMailer提供的邮件接收服务。

所有的Laravel合约都在各自的github仓库中更新。这为所有的合约,提供了一个快速参考点,以及一个单一的分离包,用于包开发。

Github参考点

6.6.1.1 合约Vs.门面

Laravel的门面提供一种简单的方法,利用Laravel服务无须输入和提示。这好于使用需要服务容器的合约方法。

但是,使用合约运行你定义依赖类。多余大多数应用,使用门面就好了。

但是,如果你真有的需要额外的松耦合,合约就可以提供,阅读下面的了解更多。

6.6.2 为什么用合约?

关于合约你可能有几个问题要问。为什么全部使用接口?不使用接口会更复杂?

下方是使用接口的重要原因:松耦合简洁性

6.6.2.1 松耦合

首先,让我们来看一个使用紧耦合缓存实现方法的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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发生了改变,我们的代码也要随之改变。

同样的,如果我们要使用其他技术(例如:redis),取代正在使用的技术(Memcached),我们还是要修改代码。

我们的类不应该用这些设定,例如,谁为他们提供数据,它是如何提供的等等。

使用下方松耦合方法,不需要绑定注入,进而优化代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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。由于合约包中没有实现方法也没有依赖关系,你可以很容易的替换合约,更换缓存技术,而无需修改代码。

6.6.2.2 简洁性

当所有的Laravel的服务,在简单接口中整洁的定义,就可以很容易的给定服务提供的功能。

合约服务为框架功能提了简洁的文档。

当你使用简单接口时,你的代码更容易理解和维护。

6.6.3 合约参考

合约 参考的门面
Illuminate\Contracts\Auth\Factory Auth
Illuminate\Contracts\Auth\PasswordBroker Password
Illuminate\Contracts\Bus\Dispatcher Bus
Illuminate\Contracts\Broadcasting\Broadcaster
Illuminate\Contracts\Cache\Repository Cache
Illuminate\Contracts\Cache\Factory Cache::driver()
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Encryption\Encrypter Crypt
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud
Illuminate\Contracts\Filesystem\Factory File
Illuminate\Contracts\Filesystem\Filesystem File
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illuminate\Contracts\Logging\Log Log
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\Mail\Mailer Mail
Illuminate\Contracts\Queue\Factory Queue::driver()
Illuminate\Contracts\Queue\Queue Queue
Illuminate\Contracts\Redis\Database Redis
Illuminate\Contracts\Routing\Registrar Route
Illuminate\Contracts\Routing\ResponseFactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Support\Arrayable
Illuminate\Contracts\Support\Jsonable
Illuminate\Contracts\Support\Renderable
Illuminate\Contracts\Validation\Factory Validator::make()
Illuminate\Contracts\Validation\Validator
Illuminate\Contracts\View\Factory View::make()
Illuminate\Contracts\View\View

6.6.4 如何使用合约

那么,如果使用一个合约的实现方法?这其实很简单。

许多类型的Laravel类,是通过服务容器解决的,包括控制器,事件监听,中间件,列队甚至是路由。

要使用合约,只需要进行类型提示,注册类的接口函数。

例如:下面的事件监听器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php

namespace App\Listeners;

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)
{
//
}
}

当事件监听器运行完成,服务容器将读取构造函数的类型提示,并注入相应的值。