# 架構 —— 契約(Contracts)
## 1、簡介
Laravel的契約是指框架提供的一系列定義核心服務的接口。比如,`Illuminate\Contracts\Queue\Queue`契約定義了隊列任務需要的方法,`Illuminate\Contracts\Mail\Mailer`契約定義了發送郵件所需要的方法。
每一個契約都有框架提供的相應實現。比如,Laravel提供了多個驅動的隊列實現,郵件實現則由?[SwiftMailer](http://swiftmailer.org/)驅動。
所有的Laravel契約都有其[GitHub庫](https://github.com/illuminate/contracts),這為所有有效的契約提供了快速入門指南,同時也可以作為獨立、解耦的包被包開發者使用。
### 1.1 契約(Contracts) VS 門面(Facades)
Laravel的門面為Laravel服務的使用提供了一個簡便的方式——不再需要從服務容器中類型提示和解析契約。然而,使用契約允許你為類定義明確的依賴,在大多數應用中,使用門面剛剛好,但是,如果你需要更多更多松耦合,那么契約無疑是合適的,繼續看下去!
## 2、為什么使用契約?
關于契約你可能存有疑問。為什么要全部使用這些契約接口?難道使用契約接口不是更復雜?下面讓我們從這兩個方面來說明使用契約接口的原因:松耦合和簡單。
### 2.1 松耦合
首先,讓我們看看一些緩存實現的緊密耦合代碼:
~~~
<?php
namespace App\Orders;
class Repository{
/**
* 緩存
*/
protected $cache;
/**
* 創建一個新的Repository實例
*
* @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變了,那么相應的,我們的代碼必須做修改。
類似的,如果我們想要替換底層的緩存技術(Memcached)為別的技術實現(Redis),我們將再一次不得不修改我們的代碼庫。我們的代碼庫應該并不知道誰提供的數據或者數據是怎么提供的。
我們可以基于一種簡單的、與提供者無關的接口來優化我們的代碼,從而替代上述那種實現:
~~~
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class Repository{
/**
* 創建一個新的Repository實例
*
* @param Cache $cache
* @return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}
~~~
現在代碼就不與任何特定提供者耦合,甚至與Laravel都是無關的。由于契約包不包含任何實現和依賴,你可以輕松的為給定契約編寫可選實現代碼,你可以隨意替換緩存實現而不用去修改任何緩存消費代碼。
### 2.2 簡單
當所有Laravel服務都統一在簡單接口中定義,很容易判斷給定服務提供的功能。契約可以充當框架特性的簡明[文檔](http://laravelacademy.org/tags/%e6%96%87%e6%a1%a3 "View all posts in 文檔")。
此外,基于簡單接口,代碼也更容易理解和維護。在一個龐大而復雜的類中,與其追蹤哪些方法時有效的,不如轉向簡單、干凈的接口。
## 3、契約列表
下面是Laravel契約列表,以及其對應的“門面”
| 契約 | 引用門面 |
| --- | --- |
| [Illuminate\Contracts\Auth\Guard](https://github.com/illuminate/contracts/blob/master/Auth/Guard.php) | Auth |
| [Illuminate\Contracts\Auth\PasswordBroker](https://github.com/illuminate/contracts/blob/master/Auth/PasswordBroker.php) | Password |
| [Illuminate\Contracts\Bus\Dispatcher](https://github.com/illuminate/contracts/blob/master/Bus/Dispatcher.php) | Bus |
| [Illuminate\Contracts\Broadcasting\Broadcaster](https://github.com/illuminate/contracts/blob/master/Broadcasting/Broadcaster.php) | |
| [Illuminate\Contracts\Cache\Repository](https://github.com/illuminate/contracts/blob/master/Cache/Repository.php) | Cache |
| [Illuminate\Contracts\Cache\Factory](https://github.com/illuminate/contracts/blob/master/Cache/Factory.php) | Cache::driver() |
| [Illuminate\Contracts\Config\Repository](https://github.com/illuminate/contracts/blob/master/Config/Repository.php) | Config |
| [Illuminate\Contracts\Container\Container](https://github.com/illuminate/contracts/blob/master/Container/Container.php) | App |
| [Illuminate\Contracts\Cookie\Factory](https://github.com/illuminate/contracts/blob/master/Cookie/Factory.php) | Cookie |
| [Illuminate\Contracts\Cookie\QueueingFactory](https://github.com/illuminate/contracts/blob/master/Cookie/QueueingFactory.php) | Cookie::queue() |
| [Illuminate\Contracts\Encryption\Encrypter](https://github.com/illuminate/contracts/blob/master/Encryption/Encrypter.php) | Crypt |
| [Illuminate\Contracts\Events\Dispatcher](https://github.com/illuminate/contracts/blob/master/Events/Dispatcher.php) | Event |
| [Illuminate\Contracts\Filesystem\Cloud](https://github.com/illuminate/contracts/blob/master/Filesystem/Cloud.php) | |
| [Illuminate\Contracts\Filesystem\Factory](https://github.com/illuminate/contracts/blob/master/Filesystem/Factory.php) | File |
| [Illuminate\Contracts\Filesystem\Filesystem](https://github.com/illuminate/contracts/blob/master/Filesystem/Filesystem.php) | File |
| [Illuminate\Contracts\Foundation\Application](https://github.com/illuminate/contracts/blob/master/Foundation/Application.php) | App |
| [Illuminate\Contracts\Hashing\Hasher](https://github.com/illuminate/contracts/blob/master/Hashing/Hasher.php) | Hash |
| [Illuminate\Contracts\Logging\Log](https://github.com/illuminate/contracts/blob/master/Logging/Log.php) | Log |
| [Illuminate\Contracts\Mail\MailQueue](https://github.com/illuminate/contracts/blob/master/Mail/MailQueue.php) | Mail::queue() |
| [Illuminate\Contracts\Mail\Mailer](https://github.com/illuminate/contracts/blob/master/Mail/Mailer.php) | Mail |
| [Illuminate\Contracts\Queue\Factory](https://github.com/illuminate/contracts/blob/master/Queue/Factory.php) | Queue::driver() |
| [Illuminate\Contracts\Queue\Queue](https://github.com/illuminate/contracts/blob/master/Queue/Queue.php) | Queue |
| [Illuminate\Contracts\Redis\Database](https://github.com/illuminate/contracts/blob/master/Redis/Database.php) | Redis |
| [Illuminate\Contracts\Routing\Registrar](https://github.com/illuminate/contracts/blob/master/Routing/Registrar.php) | Route |
| [Illuminate\Contracts\Routing\ResponseFactory](https://github.com/illuminate/contracts/blob/master/Routing/ResponseFactory.php) | Response |
| [Illuminate\Contracts\Routing\UrlGenerator](https://github.com/illuminate/contracts/blob/master/Routing/UrlGenerator.php) | URL |
| [Illuminate\Contracts\Support\Arrayable](https://github.com/illuminate/contracts/blob/master/Support/Arrayable.php) | |
| [Illuminate\Contracts\Support\Jsonable](https://github.com/illuminate/contracts/blob/master/Support/Jsonable.php) | |
| [Illuminate\Contracts\Support\Renderable](https://github.com/illuminate/contracts/blob/master/Support/Renderable.php) | |
| [Illuminate\Contracts\Validation\Factory](https://github.com/illuminate/contracts/blob/master/Validation/Factory.php) | Validator::make() |
| [Illuminate\Contracts\Validation\Validator](https://github.com/illuminate/contracts/blob/master/Validation/Validator.php) | |
| [Illuminate\Contracts\View\Factory](https://github.com/illuminate/contracts/blob/master/View/Factory.php) | View::make() |
| [Illuminate\Contracts\View\View](https://github.com/illuminate/contracts/blob/master/View/View.php) | |
## 4、如何使用契約
那么,如果獲取一個契約的實現呢?相當簡單。
Laravel中大部分類是通過[服務容器](http://laravelacademy.org/post/93.html)進行解析的,包括控制器、事件監聽器、中間件、隊列任務,甚至路由閉包等。因此,想要獲取一個契約的實現,可以在被解析的類的構造函數中類型提示該契約接口。
例如,看看事件監聽器的代碼:
~~~
<?php
namespace App\Listeners;
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)
{
//
}
}
~~~
當事件監聽器被解析時,服務容器會讀取類的構造函數上的類型提示,然后注入適當的值。想要了解更多關于服務容器的相關內容,可以查看其[文檔](http://laravelacademy.org/post/93.html)。
- 前言
- 序言
- 序言 ―― 發行版本說明
- 序言 ―― 升級指南
- 序言 ―― 貢獻代碼
- 開始
- 開始 ―― 安裝及配置
- 開始 ―― Laravel Homestead
- 基礎
- 基礎 ―― HTTP路由
- 基礎 ―― HTTP 中間件
- 基礎 ―― HTTP 控制器
- 基礎 ―― HTTP 請求
- 基礎 ―― HTTP 響應
- 基礎 ―― 視圖
- 基礎 ―― Blade模板
- 架構
- 架構 ―― 一次請求的生命周期
- 架構 ―― 應用目錄結構
- 架構 ―― 服務提供者
- 架構 ―― 服務容器
- 架構 ―― 契約
- 架構 ―― 門面
- 數據庫
- 數據庫 ―― 起步
- 數據庫 ―― 查詢構建器
- 數據庫 ―― 遷移
- 數據庫 ―― 填充數據
- Eloquent ORM
- Eloquent ORM ―― 起步
- Eloquent ORM ―― 關聯關系
- Eloquent ORM ―― 集合
- Eloquent ORM ―― 調整器
- Eloquent ORM ―― 序列化
- 服務
- 服務 ―― 用戶認證
- 服務 ―― Artisan 控制臺
- 服務 ―― Laravel Cashier(交易)
- 服務 ―― 緩存
- 服務 ―― 集合
- 服務 ―― Laravel Elixir
- 服務 ―― 加密
- 服務 ―― 錯誤&日志
- 服務 ―― 事件
- 服務 ―― 文件系統/云存儲
- 服務 ―― 哈希
- 服務 ―― 幫助函數
- 服務 ―― 本地化
- 服務 ―― 郵件
- 服務 ―― 包開發
- 服務 ―― 分頁
- 服務 ―― 隊列
- 服務 ―― Redis
- 服務 ―― Session
- 服務 ―― Envoy 任務運行器(SSH任務)
- 服務 ―― 任務調度
- 服務 ―― 測試
- 服務 ―― 驗證