# Contracts
## 簡介
Laravel 的契約是指框架提供的一系列定義核心服務的接口。例如`Illuminate\Contracts\Queue\Queue`契約定義了隊列任務需要實現的方法,而`Illuminate\Contracts\Mail\Mailer`契約定義了發送郵件所需要實現的方法。
每一個契約都有框架提供相應的實現。例如 Laravel 為隊列提供了多個驅動的實現,郵件則由[SwiftMailer](https://swiftmailer.symfony.com/)驅動實現。
所有的契約都有其[對應的 GitHub 倉庫](https://github.com/illuminate/contracts)。這為所有可用的契約提供了一個快速入門的指南,同時也可以單獨作為低耦合的擴展包被開發者使用。
### 契約 Vs. Facades
Laravel 的[facades](https://laravel-china.org/docs/laravel/5.7/facades)和輔助函數都提供了一種使用 Laravel 服務的簡單方法,既不需類型提示,也不需要從服務容器中解析解析契約。大多情況下,每一個 Facades 都有一個等效的契約。
在 Facades 中,你不需要在構造函數中做類型提示,但是契約需要你在類中明確的定義依賴。一些開發者傾向于使用契約這種明確定義依賴的方式,而其他開發者則更喜歡 Facades 帶來的便捷。
> {tip} 對于大多數的應用程序而言,不管是使用 Facades 還是契約,都可以。但是如果你在構建一個擴展包,為了方便測試,強烈建議你使用契約
## 何時使用契約
綜上所述,使用契約還是 Facades 很大程度上取決于你個人或者團隊的喜好。兩者都可以使創建強大的、測試友好的 Laravel 應用程序。只要你保持類的職責單一,你會發現使用契約還是 Facades,其實并沒有什么實質性的區別。
但是,你可能還是會對契約有些困惑。比如,為什么要全部使用接口?使用接口會不會更復雜?下面讓我們從兩個方面來聊一聊為什么使用接口:低耦合和簡單性。
### 低耦合
首先,讓我們來看一些緩存實現的高耦合代碼:
~~~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 變了,那么相應的,我們的代碼必須做修改。
同理,如果我們想要將底層的緩存技術 (Memcached) 替換成另一種緩存技術 (Redis),我們得再次修改我們的代碼庫。但其實是我們的代碼庫并不需要知道誰提供的數據或者數據是怎么提供的。
**我們可以基于一種簡單的、與擴展包無關的接口來優化我們的代碼,從而替代上面的那種實現方式:**
~~~php
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class Repository
{
/**
* 緩存實例
*/
protected $cache;
/**
* 創建一個倉庫實例
*
* @param Cache $cache
* @return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}
~~~
現在,更改之后的代碼就不與任何特定的擴展包耦合,甚至與 Laravel 都是無關的。由于契約擴展包不包含任何實現和依賴,你可以輕松的為給定的契約編寫替代實現的代碼,從而實現在不需要修改任何緩存代碼的情況下隨意替換緩存的實現。
### 簡單性
當所有的 Laravel 服務都統一使用簡單接口定義時,就會很容易判斷給定服務提供的功能。**可以將契約視為說明框架功能的簡潔文檔**
除此之外,基于簡單接口,代碼更容易理解和維護。在一個龐大而復雜的類中,與其追蹤哪些方法是有效的,倒不如直接查找一個簡單、干凈的接口來參考更為妥當。
## 如何使用契約
那么如何使用契約呢?其實很簡單。
Laravel 中有很多類都是通過[服務容器](https://laravel-china.org/docs/laravel/5.7/container),進行解析,包括控制器,以及事件監聽器、中間件、隊列任務,甚至路由閉包。所以,實現一個契約,你只需要在被解析的類的構造函數中添加契約接口即可。
例如,下面這個事件監聽器:
~~~php
<?php
namespace App\Listeners;
use App\User;
use App\Events\OrderWasPlaced;
use Illuminate\Contracts\Redis\Database;
class CacheOrderInformation
{
/**
* Redis 數據庫實現
*/
protected $redis;
/**
* 創建事件處理器實例
*
* @param Database $redis
* @return void
*/
public function __construct(Database $redis)
{
$this->redis = $redis;
}
/**
* 處理事件
*
* @param OrderWasPlaced $event
* @return void
*/
public function handle(OrderWasPlaced $event)
{
//
}
}
~~~
當事件監聽器被解析的時候,服務容器會讀取構造函數中的類型提示,并注入相應的值。想要學習更多關于服務容器的注冊細節,請參考[其文檔](https://laravel-china.org/docs/laravel/5.7/container).
## 契約參考
下表提供了所有 Laravel 契約以及其對應的 Facades :
| 契約 | 對應的 Facade |
| --- | --- |
| [Illuminate\\Contracts\\Auth\\Access\\Authorizable](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/Access/Authorizable.php) | ?? |
| [Illuminate\\Contracts\\Auth\\Access\\Gate](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/Access/Gate.php) | `Gate` |
| [Illuminate\\Contracts\\Auth\\Authenticatable](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/Authenticatable.php) | ?? |
| [Illuminate\\Contracts\\Auth\\CanResetPassword](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/CanResetPassword.php) | ? |
| [Illuminate\\Contracts\\Auth\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/Factory.php) | `Auth` |
| [Illuminate\\Contracts\\Auth\\Guard](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/Guard.php) | `Auth::guard()` |
| [Illuminate\\Contracts\\Auth\\PasswordBroker](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/PasswordBroker.php) | `Password::broker()` |
| [Illuminate\\Contracts\\Auth\\PasswordBrokerFactory](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/PasswordBrokerFactory.php) | `Password` |
| [Illuminate\\Contracts\\Auth\\StatefulGuard](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/StatefulGuard.php) | ? |
| [Illuminate\\Contracts\\Auth\\SupportsBasicAuth](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/SupportsBasicAuth.php) | ? |
| [Illuminate\\Contracts\\Auth\\UserProvider](https://github.com/illuminate/contracts/blob/laravel/5.7/Auth/UserProvider.php) | ? |
| [Illuminate\\Contracts\\Bus\\Dispatcher](https://github.com/illuminate/contracts/blob/laravel/5.7/Bus/Dispatcher.php) | `Bus` |
| [Illuminate\\Contracts\\Bus\\QueueingDispatcher](https://github.com/illuminate/contracts/blob/laravel/5.7/Bus/QueueingDispatcher.php) | `Bus::dispatchToQueue()` |
| [Illuminate\\Contracts\\Broadcasting\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Broadcasting/Factory.php) | `Broadcast` |
| [Illuminate\\Contracts\\Broadcasting\\Broadcaster](https://github.com/illuminate/contracts/blob/laravel/5.7/Broadcasting/Broadcaster.php) | `Broadcast::connection()` |
| [Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast](https://github.com/illuminate/contracts/blob/laravel/5.7/Broadcasting/ShouldBroadcast.php) | ? |
| [Illuminate\\Contracts\\Broadcasting\\ShouldBroadcastNow](https://github.com/illuminate/contracts/blob/laravel/5.7/Broadcasting/ShouldBroadcastNow.php) | ? |
| [Illuminate\\Contracts\\Cache\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Cache/Factory.php) | `Cache` |
| [Illuminate\\Contracts\\Cache\\Lock](https://github.com/illuminate/contracts/blob/laravel/5.7/Cache/Lock.php) | ? |
| [Illuminate\\Contracts\\Cache\\LockProvider](https://github.com/illuminate/contracts/blob/laravel/5.7/Cache/LockProvider.php) | ? |
| [Illuminate\\Contracts\\Cache\\Repository](https://github.com/illuminate/contracts/blob/laravel/5.7/Cache/Repository.php) | `Cache::driver()` |
| [Illuminate\\Contracts\\Cache\\Store](https://github.com/illuminate/contracts/blob/laravel/5.7/Cache/Store.php) | ? |
| [Illuminate\\Contracts\\Config\\Repository](https://github.com/illuminate/contracts/blob/laravel/5.7/Config/Repository.php) | `Config` |
| [Illuminate\\Contracts\\Console\\Application](https://github.com/illuminate/contracts/blob/laravel/5.7/Console/Application.php) | ? |
| [Illuminate\\Contracts\\Console\\Kernel](https://github.com/illuminate/contracts/blob/laravel/5.7/Console/Kernel.php) | `Artisan` |
| [Illuminate\\Contracts\\Container\\Container](https://github.com/illuminate/contracts/blob/laravel/5.7/Container/Container.php) | `App` |
| [Illuminate\\Contracts\\Cookie\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Cookie/Factory.php) | `Cookie` |
| [Illuminate\\Contracts\\Cookie\\QueueingFactory](https://github.com/illuminate/contracts/blob/laravel/5.7/Cookie/QueueingFactory.php) | `Cookie::queue()` |
| [Illuminate\\Contracts\\Database\\ModelIdentifier](https://github.com/illuminate/contracts/blob/laravel/5.7/Database/ModelIdentifier.php) | ? |
| [Illuminate\\Contracts\\Debug\\ExceptionHandler](https://github.com/illuminate/contracts/blob/laravel/5.7/Debug/ExceptionHandler.php) | ? |
| [Illuminate\\Contracts\\Encryption\\Encrypter](https://github.com/illuminate/contracts/blob/laravel/5.7/Encryption/Encrypter.php) | `Crypt` |
| [Illuminate\\Contracts\\Events\\Dispatcher](https://github.com/illuminate/contracts/blob/laravel/5.7/Events/Dispatcher.php) | `Event` |
| [Illuminate\\Contracts\\Filesystem\\Cloud](https://github.com/illuminate/contracts/blob/laravel/5.7/Filesystem/Cloud.php) | `Storage::cloud()` |
| [Illuminate\\Contracts\\Filesystem\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Filesystem/Factory.php) | `Storage` |
| [Illuminate\\Contracts\\Filesystem\\Filesystem](https://github.com/illuminate/contracts/blob/laravel/5.7/Filesystem/Filesystem.php) | `Storage::disk()` |
| [Illuminate\\Contracts\\Foundation\\Application](https://github.com/illuminate/contracts/blob/laravel/5.7/Foundation/Application.php) | `App` |
| [Illuminate\\Contracts\\Hashing\\Hasher](https://github.com/illuminate/contracts/blob/laravel/5.7/Hashing/Hasher.php) | `Hash` |
| [Illuminate\\Contracts\\Http\\Kernel](https://github.com/illuminate/contracts/blob/laravel/5.7/Http/Kernel.php) | ? |
| [Illuminate\\Contracts\\Mail\\MailQueue](https://github.com/illuminate/contracts/blob/laravel/5.7/Mail/MailQueue.php) | `Mail::queue()` |
| [Illuminate\\Contracts\\Mail\\Mailable](https://github.com/illuminate/contracts/blob/laravel/5.7/Mail/Mailable.php) | ? |
| [Illuminate\\Contracts\\Mail\\Mailer](https://github.com/illuminate/contracts/blob/laravel/5.7/Mail/Mailer.php) | `Mail` |
| [Illuminate\\Contracts\\Notifications\\Dispatcher](https://github.com/illuminate/contracts/blob/laravel/5.7/Notifications/Dispatcher.php) | `Notification` |
| [Illuminate\\Contracts\\Notifications\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Notifications/Factory.php) | `Notification` |
| [Illuminate\\Contracts\\Pagination\\LengthAwarePaginator](https://github.com/illuminate/contracts/blob/laravel/5.7/Pagination/LengthAwarePaginator.php) | ? |
| [Illuminate\\Contracts\\Pagination\\Paginator](https://github.com/illuminate/contracts/blob/laravel/5.7/Pagination/Paginator.php) | ? |
| [Illuminate\\Contracts\\Pipeline\\Hub](https://github.com/illuminate/contracts/blob/laravel/5.7/Pipeline/Hub.php) | ? |
| [Illuminate\\Contracts\\Pipeline\\Pipeline](https://github.com/illuminate/contracts/blob/laravel/5.7/Pipeline/Pipeline.php) | ? |
| [Illuminate\\Contracts\\Queue\\EntityResolver](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/EntityResolver.php) | ? |
| [Illuminate\\Contracts\\Queue\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/Factory.php) | `Queue` |
| [Illuminate\\Contracts\\Queue\\Job](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/Job.php) | ? |
| [Illuminate\\Contracts\\Queue\\Monitor](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/Monitor.php) | `Queue` |
| [Illuminate\\Contracts\\Queue\\Queue](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/Queue.php) | `Queue::connection()` |
| [Illuminate\\Contracts\\Queue\\QueueableCollection](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/QueueableCollection.php) | ? |
| [Illuminate\\Contracts\\Queue\\QueueableEntity](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/QueueableEntity.php) | ? |
| [Illuminate\\Contracts\\Queue\\ShouldQueue](https://github.com/illuminate/contracts/blob/laravel/5.7/Queue/ShouldQueue.php) | ? |
| [Illuminate\\Contracts\\Redis\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Redis/Factory.php) | `Redis` |
| [Illuminate\\Contracts\\Routing\\BindingRegistrar](https://github.com/illuminate/contracts/blob/laravel/5.7/Routing/BindingRegistrar.php) | `Route` |
| [Illuminate\\Contracts\\Routing\\Registrar](https://github.com/illuminate/contracts/blob/laravel/5.7/Routing/Registrar.php) | `Route` |
| [Illuminate\\Contracts\\Routing\\ResponseFactory](https://github.com/illuminate/contracts/blob/laravel/5.7/Routing/ResponseFactory.php) | `Response` |
| [Illuminate\\Contracts\\Routing\\UrlGenerator](https://github.com/illuminate/contracts/blob/laravel/5.7/Routing/UrlGenerator.php) | `URL` |
| [Illuminate\\Contracts\\Routing\\UrlRoutable](https://github.com/illuminate/contracts/blob/laravel/5.7/Routing/UrlRoutable.php) | ? |
| [Illuminate\\Contracts\\Session\\Session](https://github.com/illuminate/contracts/blob/laravel/5.7/Session/Session.php) | `Session::driver()` |
| [Illuminate\\Contracts\\Support\\Arrayable](https://github.com/illuminate/contracts/blob/laravel/5.7/Support/Arrayable.php) | ? |
| [Illuminate\\Contracts\\Support\\Htmlable](https://github.com/illuminate/contracts/blob/laravel/5.7/Support/Htmlable.php) | ? |
| [Illuminate\\Contracts\\Support\\Jsonable](https://github.com/illuminate/contracts/blob/laravel/5.7/Support/Jsonable.php) | ? |
| [Illuminate\\Contracts\\Support\\MessageBag](https://github.com/illuminate/contracts/blob/laravel/5.7/Support/MessageBag.php) | ? |
| [Illuminate\\Contracts\\Support\\MessageProvider](https://github.com/illuminate/contracts/blob/laravel/5.7/Support/MessageProvider.php) | ? |
| [Illuminate\\Contracts\\Support\\Renderable](https://github.com/illuminate/contracts/blob/laravel/5.7/Support/Renderable.php) | ? |
| [Illuminate\\Contracts\\Support\\Responsable](https://github.com/illuminate/contracts/blob/laravel/5.7/Support/Responsable.php) | ? |
| [Illuminate\\Contracts\\Translation\\Loader](https://github.com/illuminate/contracts/blob/laravel/5.7/Translation/Loader.php) | ? |
| [Illuminate\\Contracts\\Translation\\Translator](https://github.com/illuminate/contracts/blob/laravel/5.7/Translation/Translator.php) | `Lang` |
| [Illuminate\\Contracts\\Validation\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/Validation/Factory.php) | `Validator` |
| [Illuminate\\Contracts\\Validation\\ImplicitRule](https://github.com/illuminate/contracts/blob/laravel/5.7/Validation/ImplicitRule.php) | ? |
| [Illuminate\\Contracts\\Validation\\Rule](https://github.com/illuminate/contracts/blob/laravel/5.7/Validation/Rule.php) | ? |
| [Illuminate\\Contracts\\Validation\\ValidatesWhenResolved](https://github.com/illuminate/contracts/blob/laravel/5.7/Validation/ValidatesWhenResolved.php) | ? |
| [Illuminate\\Contracts\\Validation\\Validator](https://github.com/illuminate/contracts/blob/laravel/5.7/Validation/Validator.php) | `Validator::make()` |
| [Illuminate\\Contracts\\View\\Engine](https://github.com/illuminate/contracts/blob/laravel/5.7/View/Engine.php) | ? |
| [Illuminate\\Contracts\\View\\Factory](https://github.com/illuminate/contracts/blob/laravel/5.7/View/Factory.php) | `View` |
| [Illuminate\\Contracts\\View\\View](https://github.com/illuminate/contracts/blob/laravel/5.7/View/View.php) |