Laravel 5 引入 Contracts(契約),即一組定義框架核心服務的 interface。Contracts 讓你依賴抽象而非具體實作,實現鬆耦合、易測試、可替換的架構設計。本文深度剖析 Contracts 定義、服務容器綁定、依賴注入流程、優勢與實戰模式。
Contracts 是 Laravel 框架核心服務的介面定義集合,位於 Illuminate\Contracts\* 命名空間。每個 Contract 對應一項核心能力:
Illuminate\Contracts\Auth\Guard // 認證守衛
Illuminate\Contracts\Auth\PasswordBroker // 密碼重設
Illuminate\Contracts\Bus\Dispatcher // 指令總線
Illuminate\Contracts\Cache\Repository // 快取存取
Illuminate\Contracts\Cache\Factory // 快取工廠
Illuminate\Contracts\Config\Repository // 設定存取
Illuminate\Contracts\Container\Container // 服務容器
Illuminate\Contracts\Cookie\Factory // Cookie 管理
Illuminate\Contracts\Encryption\Encrypter // 加密服務
Illuminate\Contracts\Events\Dispatcher // 事件分發
Illuminate\Contracts\Filesystem\Factory // 檔案系統
Illuminate\Contracts\Logging\Log // 日誌
Illuminate\Contracts\Mail\Mailer // 郵件
Illuminate\Contracts\Queue\Factory // 隊列
Illuminate\Contracts\Routing\Registrar // 路由註冊
Illuminate\Contracts\Session\Session // Session
Illuminate\Contracts\Translation\Translator // 翻譯
Illuminate\Contracts\Validation\Factory // 驗證
... 共 50+ 介面
namespace App\Orders;
use SomePackage\Cache\Memcached; // 具體實作
class Repository {
protected $cache;
public function __construct(Memcached $cache) { // 硬依賴具體類
$this->cache = $cache;
}
public function find($id) {
if ($this->cache->has($id)) { ... } // 綁死 Memcached API
}
}
// 換 Redis 時:需修改所有注入點、適配 API 差異
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache; // 依賴介面
class Repository {
protected $cache;
public function __construct(Cache $cache) { // 依賴抽象
$this->cache = $cache;
}
public function find($id) {
if ($this->cache->has($id)) { ... } // 僅用介面方法
}
}
// 服務提供者綁定具體實作
// App\Providers\AppServiceProvider.php
public function register() {
$this->app->bind(
\Illuminate\Contracts\Cache\Repository::class,
\App\Services\CustomCache::class // 或 RedisCache, ArrayCache 等
);
}
register() 中,將 Contract 介面綁定至具體類別| 方法 | 用途 | 生命週期 |
|---|---|---|
$app->bind(A::class, B::class) | 每次解析新實例 | Transient |
$app->singleton(A::class, B::class) | 單例,全域共用 | Singleton |
$app->instance(A::class, $obj) | 指定具體實例 | Singleton |
$app->when(A::class)->needs(B::class)->give(C::class) | 上下文綁定 | 依場景 |
// app/Services/CustomRedisCache.php
namespace App\Services;
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Support\Facades\Redis;
class CustomRedisCache implements Repository {
public function get($key) { return Redis::get($key); }
public function put($key, $value, $minutes) { return Redis::setex($key, $minutes * 60, $value); }
public function has($key) { return Redis::exists($key); }
public function forget($key) { return Redis::del($key); }
public function flush() { return Redis::flushdb(); }
// 實作介面所有方法...
}
// app/Providers/CacheServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Cache\Repository;
use App\Services\CustomRedisCache;
class CacheServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton(Repository::class, CustomRedisCache::class);
}
}
// config/app.php 註冊提供者
'providers' => [
// ...
App\Providers\CacheServiceProvider::class,
];
use Illuminate\Contracts\Cache\Repository as Cache;
class OrderService {
protected $cache;
public function __construct(Cache $cache) {
$this->cache = $cache;
}
public function getOrder($id) {
return $this->cache->remember("order:$id", 60, fn() => Order::find($id));
}
}
| 維度 | Contracts (介面注入) | Facades (靜態代理) |
|---|---|---|
| 耦合度 | 低(依賴介面) | 高(依賴具體 Facade 類) |
| 可測試性 | 極佳(易 Mock 介面) | 需 Facade::shouldReceive() 模擬 |
| IDE 支援 | 完整(型別提示、跳轉) | 需安裝 laravel-ide-helper |
| 程式碼風格 | 建構子注入、明確依賴 | 靜態呼叫、隱式依賴 |
| 適用場景 | 核心服務、可替換組件、測試導向 | 快速原型、視圖模板、簡單專案 |
| Contract | Facade | 核心方法 |
|---|---|---|
Cache\Repository | Cache | get, put, has, forget, remember, forever |
Auth\Guard | Auth | check, user, login, logout, attempt, viaRemember |
Config\Repository | Config | get, set, has, push |
Session\Session | Session | get, put, has, forget, flush, regenerate |
Encryption\Encrypter | Crypt | encrypt, decrypt, getKey, getCipher |
Filesystem\Factory | Storage | disk, put, get, exists, delete, url |
Queue\Factory | Queue | push, later, pushRaw, connection |
Validation\Factory | Validator | make, extend, replacer |
interface OrderRepository,綁定 EloquentOrderRepository,未來可換 RedisOrderRepository$mock = Mockery::mock(Cache::class); $this->app->instance(Cache::class, $mock);{# 修改前 #}
use Cache;
class OrderController {
public function show($id) {
return Cache::remember("order:$id", 60, fn() => Order::find($id));
}
}
{# 修改後 #}
use Illuminate\Contracts\Cache\Repository as Cache;
class OrderController {
protected $cache;
public function __construct(Cache $cache) {
$this->cache = $cache;
}
public function show($id) {
return $this->cache->remember("order:$id", 60, fn() => Order::find($id));
}
}
Contracts 是 Laravel 實現「依賴倒置原則」的關鍵基礎設施。善用 Contracts,能讓你的應用在擴展第三方服務、單元測試、架構演進時保持極高的靈活性與可維護性。