這篇文章主要介紹了關於PHP中的服務容器與依賴注入,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
依賴注入
當A類需要依賴於B類,也就是說需要在A類中執行個體化B類的對象來使用時候,如果B類中的功能發生改變,也會導致A類中使用B類的地方也要跟著修改,導致A類與B類高耦合。這個時候解決方式是,A類應該去依賴B類的介面,把具體的類的執行個體化交給外部。
就拿我們業務中常用的通知模組來說。
<?php/** * 定義了一個訊息類 * Class Message */class Message{ public function seed() { return 'seed email'; }}/* * 訂單產生的時候 需要發送訊息 */class Order{ protected $messager = ''; function __construct() { $this->messager = new Message(); } public function seed_msg() { return $this->messager->seed(); }}$Order = new Order();$Order->seed_msg();
上面的代碼是我們傳統的寫法。首先由個訊息發送的類。然後在我們需要發送訊息的地方,調用發送訊息的介面。有一天你需要添加一個傳送簡訊的介面以滿足不同的需求。那麼你會發現你要再Message
類裡面做修改。同樣也要再Order
類裡面做修改。這樣就顯得很麻煩。這個時候就有了依賴注入的思路。下面把代碼做一個調整
<?php/** * 為了約束我們先定義一個訊息介面 * Interface Message */interface Message{ public function seed();}/** * 有一個發送郵件的類 * Class SeedEmail */class SeedEmail implements Message{ public function seed() { return 'seed email'; // TODO: Implement seed() method. }}/** *新增一個傳送簡訊的類 * Class SeedSMS */class SeedSMS implements Message{ public function seed() { return 'seed sms'; // TODO: Implement seed() method. }}/* * 訂單產生的時候 需要發送訊息 */class Order{ protected $messager = ''; function __construct(Message $message) { $this->messager = $message; } public function seed_msg() { return $this->messager->seed(); }}//我們需要發送郵件的時候$message = new SeedEmail();//將郵件發送對象作為參數傳遞給Order$Order = new Order($message);$Order->seed_msg();//我們需要傳送簡訊的時候$message = new SeedSMS();$Order = new Order($message);$Order->seed_msg();
這樣我們就實現了依賴注入的思路,是不是很方便擴充了。
服務容器
我理解的服務容器就是一個自動產生類的工廠。
<?php/** * 為了約束我們先定義一個訊息介面 * Interface Message */interface Message{ public function seed();}/** * 有一個發送郵件的類 * Class SeedEmail */class SeedEmail implements Message{ public function seed() { return 'seed email'; // TODO: Implement seed() method. }}/** *新增一個傳送簡訊的類 * Class SeedSMS */class SeedSMS implements Message{ public function seed() { return 'seed sms'; // TODO: Implement seed() method. }}/** * 這是一個簡單的服務容器 * Class Container */class Container{ protected $binds; protected $instances; public function bind($abstract, $concrete) { if ($concrete instanceof Closure) { $this->binds[$abstract] = $concrete; } else { $this->instances[$abstract] = $concrete; } } public function make($abstract, $parameters = []) { if (isset($this->instances[$abstract])) { return $this->instances[$abstract]; } array_unshift($parameters, $this); return call_user_func_array($this->binds[$abstract], $parameters); }}//建立一個訊息工廠$message = new Container();//將傳送簡訊註冊綁定到工廠裡面$message->bind('SMS',function (){ return new SeedSMS();});//將發送郵件註冊綁定到工廠$message->bind('EMAIL',function (){ return new SeedEmail();});//需要傳送簡訊的時候$SMS = $message->make('SMS');$SMS->seed();
container
是一個簡單的服務容器裡面有bind
,make
兩個方法
bind
是向容器中綁定服務物件。make
則是從容器中取出對象。
bind
在bind
方法中需要傳入一個 concrete
我們可以傳入一個執行個體對象或者是一個閉包函數。
可以看到我這全使用的是閉包函數,其實也可以這樣寫
$sms = new SeedSMS();$message->bind('SMS',$sms);
後面這種寫法與閉包相比的區別就是我們需要先執行個體化對象才能往容易中綁定服務。而閉包則是我們使用這個服務的時候才去執行個體化對象。可以看出閉包是有很多的優勢的。
make
make
方法就從容器中出去方法。裡面首先判斷了instances
變數中是否有當前以及存在的服務物件,如果有直接返回。如果沒有那麼會通過 call_user_func_array
返回一個對象。call_user_func_array
的使用可以查看
PHP 中 call_user_func 的使用
以上就是本文的全部內容,希望對大家的學習有所協助,更多相關內容請關注topic.alibabacloud.com!