IoC容器
基本使用
Laravel 的控制反轉容器(Ioc Container)是一個管理類別依賴關係的強大工具。 依賴注入是一種避免類別依賴關係被寫死(hard-coded)的方法。 反而言之,讓依賴關係在執行階段時進行注入,這樣能使得依賴關係更容易彈性的交換使用。
了解 Laravel 控制反轉容器是必要的,這不單只為了貢獻到 Laravel 核心,並能建立強大應用程式。
自動分辨
控制反轉容器有兩種方式來分析依賴關係:透過「閉包回呼」函式或「自動分析」。 首先我們將探討閉包回呼部分。 假設有一種"類型"綁定到容器中。:
綁定一個類型到容器
App::bind('foo', function($app)
{
return new FooBar;
});
從容器中分析一個類型
$value = App::make('foo');
當 App::make
函式被呼叫後,閉包回呼內容將被執行並回傳結果。
有時候,你或許想要被綁定到容器的閉包回呼函式執行時,僅被分析一次並回傳相同的物件實例:
綁定一個"被共享"類型到容器
App::singleton('foo', function()
{
return new FooBar;
});
你也可能使用 instance
方法來綁定一個已存在的物件實例到容器:
綁定一個已存在的實例到容器
$foo = new Foo;
App::instance('foo', $foo);
自動分辨
控制反轉容器相當強大,足夠在很多的情境,根本沒有任何設定下,分析出類別來。例如:
分析一個類別
class FooBar {
public function __construct(Baz $baz)
{
$this->baz = $baz;
}
}
$fooBar = App::make('FooBar');
注意,即便我們未註冊 FooBar 類別到容器中,容器仍然能夠分辦出類別並將 Baz
依賴關係自動注入
當一種類型尚未被綁定到容器中,將會使用 PHP 的 Reflection facilities 去檢查類別以及讀取建構的類型指定。 利用這個特點,容器將會自動的建立類別的實例。
然而,在一些案例中,一個類別也許依賴一個介面的實作,並非一個"具體類型"。 當在這種案例時,使用 App::bind
方法通知容器使用介面實作注入:
綁定介面到一個實作
App::bind('UserRepositoryInterface', 'DbUserRepository');
現在讓我們思索一下這個控制器:
class UserController extends BaseController {
public function __construct(UserRepositoryInterface $users)
{
$this->users = $users;
}
}
我們綁定 UserRepositoryInterface
到具體類型後,當控制器被建立後, DbUserRepository
將自動地被注入。
實際使用
Laravel 提供幾個機會去使用控制反轉容器來增加你的應用程式強性和可測試。 分析控制器就是最主要的範例。 所有的控制器都透過控制反轉容器,這意味著你能夠在控制器建構時,給予依賴關係的類型指定,接著這些依賴的部分就會自動的被注入。
類型指定控制依賴
class OrderController extends BaseController {
public function __construct(OrderRepository $orders)
{
$this->orders = $orders;
}
public function getIndex()
{
$all = $this->orders->all();
return View::make('orders', compact('all'));
}
}
在這個範例中, OrderRepository
類別將自動被注入到這個控制器中。 這表示當 單元測試 (unit testing) 進行 "mock" 時, 將會綁定 OrderRepository
到容器中並注入到控制器,無痛的使用資庫層操作。
路由過濾器 、 視圖Composers 與 使用類別傾聽器 也都被分辦到控制反轉容器中。 當你註冊它們後,簡單的給個類別名稱就能夠使用:
其它控制反轉容器的使用範例
Route::filter('foo', 'FooFilter');
View::composer('foo', 'FooComposer');
Event::listen('foo', 'FooHandler');
服務提供者
服務供應器是群組關聯控制反轉容器的一個好方法。 它們可以算是一個應用程式的啟動元件。 透過這個服務供應器,你可以註冊一個自訂的驗證驅動器,應用程式類別庫等到控制反轉容器,或甚至設定一個 Artisan 指令。
事實上,大部分的 Lravel 的核心元件都有服務應供器。 所有已註冊的服務應供器都列表在 app/config/app.php
中 providers
的陣列中。
建立服務供應器,只要簡單的繼承 Illuminate\Support\ServiceProvider
類別並定義 register
方法:
定義服務供應器
use Illuminate\Support\ServiceProvider;
class FooServiceProvider extends ServiceProvider {
public function register()
{
$this->app->bind('foo', function()
{
return new Foo;
});
}
}
注意 register
方法中,可以使用 $this->app
屬性來進行控制反轉容器的綁定。 一旦你已建立供應器並已經準備註冊它,只需要簡單將它加到你 app
設定檔中的 providers
陣列。
在執行階段,你也可以使用 App::register
這個方法來註冊你的服務供應器:
在執行時候註冊一個服務提供者
App::register('FooServiceProvider');
容器事件
容器事件是每當控制反轉容器執行分析物件時所觸發。 你能夠透過 resolving
方法監聽這些事件:
註冊分析監聽器
App::resolving(function($object)
{
//
});
注意,被分析出來的物件將會被傳至回呼函式中。