前陣子看了點Laravel源碼,越看越亂,網上大部分中文文檔都是直譯,比較生澀難懂,還是決定看英文文檔順便就我的理解做下翻譯整理記錄下來
簡介
Larvel的Contracts是一系列接口,它們定義了由框架提供的核心服務。例如,Illuminate\Contracts\Queue\Queue
定義了隊列工作需要的方法,Illuminate\Contracts\Mail\Mailer
定義了發送郵件的方法。
每個contract都有框架提供的對應實現。例如,Laravel提供了不同驅動下的queue實現,還有一個SwiftMailer的mailer實現
所有的Laravel contracts都存放在他們自己的GitHub倉庫中。這提供了一個快速導航,可以讓你定位到可用的contracts,還有獨立的,解耦的package讓package開發者可以用來開發。
Contracts和門面
Laravel的門面提供了一個利用Laravel服務的簡潔方法,不需要類型提示也不需要從服務容器中解析contracts。然而,用contracts可以為一個類定義明確的依賴。對于大多數應用,門面很好用。當然,如果你需要contracts提供的極度松耦合,那就讀下去!
為什么要用Contracts
你可能有很多關于contracts的問題。為什么要用接口?用接口會不會更復雜?讓我們從下面幾點來挖掘用接口的理由:松耦合和簡潔。
松耦合
首先,讓我們回顧一段緩存首先緊耦合的代碼:
<?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)) {
//
}
}
}
在這個類中,代碼對指定緩存實現緊耦合。這是一個緊耦合因為我們依賴于vendor包內的固定的緩存。如果那個package內的API發生的變化,我們的代碼也要變。
同樣的,如果我們想要把底層緩存技術(Mecached)替換成另一個技術(Redis),我們必須修改倉庫。我們的倉庫無法得知誰提供了數據還有他們如何提供。
取而代之,我們可以改進我們的代碼,讓它們依賴于一個簡單的,vendor無關的接口:
<?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;
}
}
現在代碼不耦合于任何特定的vendor或者Laravel。因為contracts不包含任何實現和依賴,可以輕松為contract編寫可變實現,你可以替換緩存實現而不用修改任何它服務的代碼。
簡潔
當所有的Laravel服務都由簡單接口定義,明確給定服務提供的功能就會變得簡單。contracts就像框架特征的一個簡潔文檔。
另外,當依賴簡單的接口,你的代碼理解和維護起來就更簡單。不用再從龐大,復雜的類中查看哪個方法可以用,你只要參考簡單干凈的接口就可以了。
如何使用Contracts
你如何獲得一個contract實現?這很簡單。
很多類型的類都是通過服務器容器解析的,包括控制器、事件監聽、中間件、隊列工作甚至路由閉包。所以,你只需要在要解析的類的構造函數中類型提示接就可以獲得contract的實現了。
例如,看看下面這個事件監聽:
<?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)
{
//
}
}
當你的事件監聽被解析,服務容器會讀取構造函數類型提示,然后注入適當的值。