一察迟、名詞解釋
IoC - Inversion of Control 控制反轉
DI - Dependency Injection 依賴注入
依賴倒置原則(DIP)
:一種軟件架構設計的原則(抽象概念),依賴倒置原則,它轉換了依賴盅抚,抽象模塊不依賴于具體模塊的實現(xiàn),而具體模塊依賴于抽象模塊定義的接口。通俗的講,就是抽象模塊定義接口莺琳,具體模塊負責實現(xiàn)。载慈。
控制反轉(IoC)
:一種反轉流惭等、依賴和接口的方式(DIP的具體實現(xiàn)方式)。
依賴注入(DI)
:IoC的一種實現(xiàn)方式办铡,用來反轉依賴(IoC的具體實現(xiàn)方式)辞做。
IoC容器
:依賴注入的框架,用來映射依賴寡具,管理對象創(chuàng)建和生存周期(DI框架)秤茅。
依賴注入(DI)是一個過程,通過這個過程童叠,對象可以通過構造函數(shù)參數(shù)嫂伞,工廠方法的參數(shù)或者在構造或返回對象實例后設置的屬性來定義它們的依賴關系從工廠方法。
依賴注入和控制反轉說的實際上是同一個東西拯钻,它們是一種設計模式,這種設計模式用來減少程序間的耦合撰豺。依賴注入和控制反轉是對同一件事情的不同描述粪般,從某個方面講,就是它們描述的角度不同污桦。
1亩歹、依賴注入是從應用程序的角度在描述,可以把依賴注入凡橱,即:應用程序依賴容器創(chuàng)建并注入它所需要的外部資源小作;
2、而控制反轉是從容器的角度在描述稼钩,即:容器控制應用程序顾稀,由容器反向的向應用程序注入應用程序所需要的外部資源。
整個過程中參與者都有誰坝撑?
一般有三方參與者静秆,一個是某個對象粮揉;一個是IoC/DI的容器;另一個是某個對象的外部資源抚笔。
1扶认、某個對象指的就是任意的、普通的PHP對象;
2殊橙、IoC/DI的容器簡單點說就是指用來實現(xiàn)IoC/DI功能的一個框架程序辐宾;
3、對象的外部資源指的就是對象需要的膨蛮,但是是從對象外部獲取的叠纹,都統(tǒng)稱資源,比如:對象需要的其它對象鸽疾、或者是對象需要的文件資源等等吊洼。
二、控制反轉IoC進一步解釋
1制肮、如何反轉冒窍,反轉了什么
控制反轉顧名思義,就是要去反轉控制權豺鼻,那么到底是哪些控制被反轉了综液?控制反轉是指把對象的依賴管理從內部轉移至外部。
在單一職責原則的設計下儒飒,很少有單獨一個對象就能完成的任務谬莹。大多數(shù)任務都需要復數(shù)的對象來協(xié)作完成,這樣對象與對象之間就有了依賴桩了。一開始對象之間的依賴關系是自己解決的附帽,需要什么對象了就New一個出來用,控制權是在對象本身井誉。但是這樣耦合度就非常高蕉扮,可能某個對象的一點小修改就會引起連鎖反應,需要把依賴的對象一路修改過去颗圣。
如果依賴對象的獲得被反轉喳钟,具體生成什么依賴對象和什么時候生成都由對象之外的IOC容器來決定。對象只要在用到依賴對象的時候能獲取到就可以了在岂,常用的方式有依賴注入和依賴查找(Dependency Lookup)奔则。這樣對象與對象之間的耦合就被移除到了對象之外,后續(xù)即使有依賴修改也不需要去修改原代碼了蔽午。
2易茬、依賴注入
控制反轉是把對象之間的依賴關系提到外部去管理,可依賴是提到對象外面了及老,對象本身還是要用到依賴對象的疾呻,這時候就要用到依賴注入了除嘹。顧名思義,應用需要把對象所需要的依賴從外部注入進來岸蜗。IoC有2種常見的實現(xiàn)方式:依賴注入和服務定位尉咕。
控制反轉(IoC)一種重要的方式,就是將依賴對象的創(chuàng)建和綁定轉移到被依賴對象類的外部來實現(xiàn)璃岳。
依賴注入(DI)年缎,它提供一種機制,將需要依賴(具體模塊)對象的引用傳遞給被依賴(抽象模塊)對象铃慷。
實現(xiàn)方式:
方法一
構造函數(shù)注入
構造函數(shù)函數(shù)注入傳遞依賴单芜。根據DIP原則,我們知道抽象模塊不應該依賴于具體模塊犁柜,兩者應該依賴于抽象洲鸠。那么構造函數(shù)的參數(shù)應該是一個抽象類型。
方法二
屬性注入
屬性注入是通過屬性來傳遞依賴馋缅。
方法三
接口注入
相比構造函數(shù)注入和屬性注入扒腕,接口注入顯得有些復雜,使用也不常見萤悴。具體思路是先定義一個接口瘾腰,包含一個設置依賴的方法。然后依賴類覆履,繼承并實現(xiàn)這個接口蹋盆。
對于大型項目來說,相互依賴的組件比較多硝全。如果還用手動的方式栖雾,自己來創(chuàng)建和注入依賴的話,顯然效率很低伟众,而且往往還會出現(xiàn)不可控的場面岩灭。正因如此,IoC容器誕生了赂鲤。IoC容器實際上是一個DI框架,它能簡化我們的工作量柱恤。
它包含以下幾個功能:
1数初、動態(tài)創(chuàng)建、注入依賴對象梗顺。
2泡孩、管理對象生命周期。
3寺谤、映射依賴關系仑鸥。
三吮播、PHP代碼示例
PHP具體代碼實現(xiàn)的思路:
1、Ioc容器維護binding數(shù)組記錄bind方法傳入的鍵值對如:log=>FileLog, user=>User
2眼俊、在ioc->make('user')的時候意狠,通過反射拿到User的構造函數(shù),拿到構造函數(shù)的參數(shù)疮胖,發(fā)現(xiàn)參數(shù)是User的構造函數(shù)參數(shù)log,然后根據log得到FileLog环戈。
3、這時候我們只需要通過反射機制創(chuàng)建 $filelog = new FileLog();
4澎灸、通過newInstanceArgs然后再去創(chuàng)建new User($filelog);
interface log{
public function write();
}
// 文件記錄日志
class FileLog implements Log{
public function write(){
echo 'file log write...';
}
}
// 數(shù)據庫記錄日志
class DatabaseLog implements Log{
public function write(){
echo 'database log write...';
}
}
class User{
protected $log;
public function __construct(Log $log){
$this->log = $log;
}
public function login(){
// 登錄成功院塞,記錄登錄日志
echo 'login success...';
$this->log->write();
}
}
class Ioc{
public $binding = [];
public function bind($abstract, $concrete){
//這里為什么要返回一個closure呢?因為bind的時候還不需要創(chuàng)建User對象性昭,所以采用closure等make的時候再創(chuàng)建FileLog;
$this->binding[$abstract]['concrete'] = function ($ioc) use ($concrete) {
return $ioc->build($concrete);
};
}
public function make($abstract){
// 根據key獲取binding的值
$concrete = $this->binding[$abstract]['concrete'];
return $concrete($this);
}
// 創(chuàng)建對象
public function build($concrete) {
$reflector = new ReflectionClass($concrete);
$constructor = $reflector->getConstructor();
if(is_null($constructor)) {
return $reflector->newInstance();
}
$dependencies = $constructor->getParameters();
$instances = $this->getDependencies($dependencies);
return $reflector->newInstanceArgs($instances);
}
// 獲取參數(shù)的依賴
protected function getDependencies($paramters) {
$dependencies = [];
foreach ($paramters as $paramter) {
$dependencies[] = $this->make($paramter->getClass()->name);
}
return $dependencies;
}
}
//實例化IoC容器
$ioc = new Ioc();
$ioc->bind('log','FileLog');
$ioc->bind('user','User');
$user = $ioc->make('user');
$user->login();
參考
1拦止、聊一聊PHP的依賴注入(DI) 和 控制反轉(IoC)
2、原則&模式|理解DIP糜颠、IoC汹族、DI以及IoC容器
3、Laravel 服務容器實例教程 —— 深入理解控制反轉(IoC)和依賴注入(DI)(推薦閱讀
)
4括蝠、如何實現(xiàn) IoC 容器和服務提供者是什么概念(推薦閱讀
)
5鞠抑、 [Laravel 5.8 文檔 ] 底層原理 —— 服務容器(推薦閱讀
)
6、PHP反射機制實現(xiàn)自動依賴注入
7忌警、那些年搞不懂的高深術語——依賴倒置?控制反轉?依賴注入?面向接口編程
8搁拙、控制反轉(IOC)和依賴注入(DI)(推薦閱讀
)
9、控制反轉和依賴注入的理解
10法绵、談談php里的IOC控制反轉箕速,DI依賴注入