Contract
簡介
Laravel 的「Contract」是一組介面,這些介面定義了框架提供的核心服務。舉例來說,Illuminate\Contracts\Queue\Queue
Contract 定義了佇列任務所需要的方法;而 Illuminate\Contracts\Mail\Mailer
Contract 則定義了寄送 E-Mail 所需要的方法。
在 Laravel 中,每個 Contract 都有其相對應的實作。舉例來說,在 Laravel 中的 Queue 實作支援多種 Driver,而 Mailer 實作則由 Symfony Mailer 驅動。
所有的 Laravel Contract 都放在 Contract 自己的 GitHub 儲存庫內。使用該儲存庫,就可以快速參照到所有的 Contract,並且,在製作使用到 Laravel 服務的套件時,也可以作為一個單一、解藕的套件來使用。
Contract Vs. Facade
使用 Laravel 的 Facade 或輔助函式,就可以在不使用型別提示,或是從 Service Container 中解析 Contract 的情況下輕鬆使用各種 Laravel 服務。在大多數的情況下,各個 Facade 都有其對應的 Contract。
使用 Facade 時,不需要在類別的建構函式內要求這些類別。而與 Contract 與 Facade 不同的是,Contract 可以讓你為類別顯式 (Explicitly) 定義其相依性項目。某些開發人員偏好顯式定義相依性項目,因此他們也偏好使用 Contract;而其他開發人員則比較享受 Facade 帶來的方便性。一般來說,大多數專案在開發期間都可以使用 Facade 而不會遇到問題。
什麼時候使用 Contract
要決定使用 Contract 還是 Facade,取決於個人以及開發團隊的偏好。不論使用 Contract 還是 Facade,在 Laravel 中都可獲得相同的強健性與可測試性。Contract 與 Facade 並非互斥。你可以在專案中某些部分使用 Facade、其他部分則使用 Contract。只要能保持類別的職責專一,使用 Contract 或 Facade 基本上就沒什麼差別。
通常來說,在開發期間,使用 Facade 對於大多數的專案來說都不會遇到什麼問題。不過若你在做的是會整合多個 PHP 框架的套件,則可以使用 illuminate/contracts
套件來定義與 Laravel 服務的整合。不需要在套件的 composer.json
檔中 require 整個 Laravel 的實際 (Concrete) 實作。
如何使用 Contract
那麼,如何取得某個 Contract 的實作呢?其實很簡單。
在 Laravel 中,許多類型的類別都會通過 Service Container 來解析。包含 Controller、Event Listener、Middleware、放入佇列的 Job、甚至是 Route 閉包。因此,若要取得一個 Contract 的實作,只需要在被解析類別的 Contractor 上對介面進行「型別提示 (Type-Hint)」即可。
舉例來說,來看看這個 Event Listner:
1<?php23namespace App\Listeners;45use App\Events\OrderWasPlaced;6use App\Models\User;7use Illuminate\Contracts\Redis\Factory;89class CacheOrderInformation10{11 /**12 * The Redis factory implementation.13 *14 * @var \Illuminate\Contracts\Redis\Factory15 */16 protected $redis;1718 /**19 * Create a new event handler instance.20 *21 * @param \Illuminate\Contracts\Redis\Factory $redis22 * @return void23 */24 public function __construct(Factory $redis)25 {26 $this->redis = $redis;27 }2829 /**30 * Handle the event.31 *32 * @param \App\Events\OrderWasPlaced $event33 * @return void34 */35 public function handle(OrderWasPlaced $event)36 {37 //38 }39}
1<?php23namespace App\Listeners;45use App\Events\OrderWasPlaced;6use App\Models\User;7use Illuminate\Contracts\Redis\Factory;89class CacheOrderInformation10{11 /**12 * The Redis factory implementation.13 *14 * @var \Illuminate\Contracts\Redis\Factory15 */16 protected $redis;1718 /**19 * Create a new event handler instance.20 *21 * @param \Illuminate\Contracts\Redis\Factory $redis22 * @return void23 */24 public function __construct(Factory $redis)25 {26 $this->redis = $redis;27 }2829 /**30 * Handle the event.31 *32 * @param \App\Events\OrderWasPlaced $event33 * @return void34 */35 public function handle(OrderWasPlaced $event)36 {37 //38 }39}
當 Event Listner 被解析時,Service Container 會讀取該類別中 Constractor 的型別提示,並插入合適的值。要瞭解更多有關如何向 Service Container 註冊東西的資訊,請參考 Service Container 的說明文件。
Contract 對照表
下列表格是所有 Laravel Contract 與其對應 Facade 的對照表: