依賴注入
依賴注入是個花哨的名詞,事實上是指:類別的依賴透過構造器或在某些情況下透過「setter」方法「注入」。先看一段 Laravel 控制器裡的程式碼實例:
<?php namespace App\Http\Controllers; use Illuminate\Routing\Controller; use App\Users\Repository as UserRepository; class UserController extends Controller { /** * 用户 Repository 的实例。 */ protected $users; /** * 创建一个新的控制器实例。 * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * 显示指定 ID 的用户。 * * @param int $id * @return View */ public function show($id) { $user_info = $this->users->find($id); return view('user', ['user_info' => $user_info]); } }
Laravel 透過服務容器來管理類別依賴並進行依賴注入。如果使用一個介面作為函數參數的類型提示,這個時候就需要將指定的實作綁定到介面上面:
interface EventPusher { public function send($data); }
class RedisEventPusher implements EventPusher { public function send($data) { // } }
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
use App\Contracts\EventPusher; /** * 创建一个新的类实例。 * * @param EventPusher $pusher * @return void */ public function __construct(EventPusher $pusher) { $this->pusher = $pusher; }
這個就是所謂的面向介面編程,介面可以理解為一個規範、一個約束。高層模組不直接依賴低層模組,它們都應該依賴抽象(指介面)。
使用依賴注入,最重要的一點好處就是有效的分離了物件和它所需的外部資源,使得它們鬆散耦合,有利於功能復用,更重要的是使得程式的整個體系結構變得非常靈活。
控制反轉
控制反轉(Inversion of Control,縮寫為IoC),是物件導向程式設計中的一種設計原則。其中**最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫做「依賴查找」(Dependency Lookup)。透過控制反轉,物件在被創建的時候,由一個調控系統內所有物件的外界實體,將其所依賴的物件的引用傳遞給它。也可以說,依賴被注入到物件中。
<?php /** * 没有IoC/DI的时候,常规的A类使用C类的示例 */ /** * Class c */ class c { public function say() { echo 'hello'; } } /** * Class a */ class a { private $c; public function __construct() { $this->c = new C(); // 实例化创建C类 } public function sayC() { echo $this->c->say(); // 调用C类中的方法 } } $a = new a(); $a->sayC();
當有了IoC/DI的容器後,A類不再主動去創建C了,如下圖所示:
而是被動等待,等待IoC/DI的容器獲取一個C
而是被動等待,等待IoC/DI的容器獲取一個C的實例,然後反向的注入到A類中,如下圖所示:
<?php /** * 当有了IoC/DI的容器后,a类依赖c实例注入的示例 */ /** * Class c */ class c { public function say() { echo 'hello'; } } /** * Class a */ class a { private $c; public function setC(C $c) { $this->c = $c; // 实例化创建C类 } public function sayC() { echo $this->c->say(); // 调用C类中的方法 } } $c = new C(); $a = new a(); $a->setC($c); $a->sayC();