PHP依賴注入(DI)和控制反轉(zhuǎn)(IoC)詳解
首先依賴注入和控制反轉(zhuǎn)說的是同一個東西,是一種設(shè)計模式,這種設(shè)計模式用來減少程序間的耦合,鄙人學(xué)習(xí)了一下,看TP官網(wǎng)還沒有相關(guān)的文章,就寫下這篇拙作介紹一下這種設(shè)計模式,希望能為TP社區(qū)貢獻(xiàn)一些力量。
首先先別追究這個設(shè)計模式的定義,否則你一定會被說的云里霧里,筆者就是深受其害,百度了N多文章,都是從理論角度來描述,充斥著大量的生澀詞匯,要么就是java代碼描述的,也生澀。
不管怎么樣,總算弄清楚一些了,下面就以php的角度來描述一下依賴注入這個概念。
先假設(shè)我們這里有一個類,類里面需要用到數(shù)據(jù)庫連接,按照最最原始的辦法,我們可能是這樣寫這個類的:
class example { private $_db; function __construct(){ include "./Lib/Db.php"; $this->_db = new Db("localhost","root","123456","test"); } function getList(){ $this->_db->query("......");//這里具體sql語句就省略不寫了 } }
過程:
在構(gòu)造函數(shù)里先將數(shù)據(jù)庫類文件include進(jìn)來;
然后又通過new Db并傳入數(shù)據(jù)庫連接信息實例化db類;
之后getList方法就可以通過$this->_db來調(diào)用數(shù)據(jù)庫類,實現(xiàn)數(shù)據(jù)庫操作。
看上去我們實現(xiàn)了想要的功能,但是這是一個噩夢的開始,以后example1,example2,example3....越來越多的類需要用到db組件,如果都這么寫的話,萬一有一天數(shù)據(jù)庫密碼改了或者db類發(fā)生變化了,豈不是要回頭修改所有類文件?
ok,為了解決這個問題,工廠模式出現(xiàn)了,我們創(chuàng)建了一個Factory方法,并通過Factory::getDb()方法來獲得db組件的實例:
class Factory { public static function getDb(){ include "./Lib/Db.php"; return new Db("localhost","root","123456","test"); } }
sample類變成:
class example { private $_db; function __construct(){ $this->_db = Factory::getDb(); } function getList(){ $this->_db->query("......");//這里具體sql語句就省略不寫了 } }
這樣就完美了嗎?再次想想一下以后example1,example2,example3....所有的類,你都需要在構(gòu)造函數(shù)里通過Factory::getDb();獲的一個Db實例,實際上由原來的直接與Db類的耦合變?yōu)榱撕虵actory工廠類的耦合,工廠類只是幫你把數(shù)據(jù)庫連接信息給包裝起來了,雖然當(dāng)數(shù)據(jù)庫信息發(fā)生變化時只要修改Factory::getDb()方法就可以了,但是突然有一天工廠方法需要改名,或者getDb方法需要改名,你又怎么辦?當(dāng)然這種需求、、但有時候確實存在這種情況,一種解決方式是:
我們不從example類內(nèi)部實例化Db組件,我們依靠從外部的注入,什么意思呢?看下面的例子:
class example { private $_db; function getList(){ $this->_db->query("......");//這里具體sql語句就省略不寫了 } //從外部注入db連接 function setDb($connection){ $this->_db = $connection; } } //調(diào)用 $example = new example(); $example->setDb(Factory::getDb());//注入db連接 $example->getList();
這樣一來,example類完全與外部類解除耦合了,你可以看到Db類里面已經(jīng)沒有工廠方法或Db類的身影了。我們通過從外部調(diào)用example類的setDb方法,將連接實例直接注入進(jìn)去。這樣example完全不用關(guān)心db連接怎么生成的了。
這就叫依賴注入,實現(xiàn)不是在代碼內(nèi)部創(chuàng)建依賴關(guān)系,而是讓其作為一個參數(shù)傳遞,這使得我們的程序更容易維護(hù),降低程序代碼的耦合度,實現(xiàn)一種松耦合。
這還沒完,我們再假設(shè)example類里面除了db還要用到其他外部類,我們通過:
$example->setDb(Factory::getDb());//注入db連接 $example->setFile(Factory::getFile());//注入文件處理類 $example->setImage(Factory::getImage());//注入Image處理類 ...
我們沒完沒了的寫這么多set?累不累?
ok,為了不用每次寫這么多行代碼,我們又去弄了一個工廠方法:
class Factory { public static function getExample(){ $example = new example(); $example->setDb(Factory::getDb());//注入db連接 $example->setFile(Factory::getFile());//注入文件處理類 $example->setImage(Factory::getImage());//注入Image處理類 return $expample; } }
實例化example時變?yōu)椋?/p>
$example=Factory::getExample(); $example->getList();
似乎完美了,但是怎么感覺又回到了上面第一次用工廠方法時的場景?這確實不是一個好的解決方案,所以又提出了一個概念:容器,又叫做IoC容器、DI容器。
我們本來是通過setXXX方法注入各種類,代碼很長,方法很多,雖然可以通過一個工廠方法包裝,但是還不是那么爽,好吧,我們不用setXXX方法了,這樣也就不用工廠方法二次包裝了,那么我們還怎么實現(xiàn)依賴注入呢?
這里我們引入一個約定:在example類的構(gòu)造函數(shù)里傳入一個名為Di $di的參數(shù),如下:
class example { private $_di; function __construct(Di &$di){ $this->_di = $di; } //通過di容器獲取db實例 function getList(){ $this->_di->get('db')->query("......");//這里具體sql語句就省略不寫了 } } $di = new Di(); $di->set("db",function(){ return new Db("localhost","root","root","test"); }); $example = new example($di); $example->getList();
Di就是IoC容器,所謂容器就是存放我們可能會用到的各種類的實例,我們通過$di->set()設(shè)置一個名為db的實例,因為是通過回調(diào)函數(shù)的方式傳入的,所以set的時候并不會立即實例化db類,而是當(dāng)$di->get('db')的時候才會實例化,同樣,在設(shè)計di類的時候還可以融入單例模式。
這樣我們只要在全局范圍內(nèi)申明一個Di類,將所有需要注入的類放到容器里,然后將容器作為構(gòu)造函數(shù)的參數(shù)傳入到example,即可在example類里面從容器中獲取實例。當(dāng)然也不一定是構(gòu)造函數(shù),你也可以用一個 setDi(Di $di)的方法來傳入Di容器,總之約定是你制定的,你自己清楚就行。
這樣一來依賴注入以及關(guān)鍵的容器概念已經(jīng)介紹完畢,剩下的就是在實際中使用并理解它吧!
相關(guān)文章
PHP人民幣金額數(shù)字轉(zhuǎn)中文大寫的函數(shù)代碼
在網(wǎng)上看到一個非常有趣的PHP人民幣金額數(shù)字轉(zhuǎn)中文大寫的函數(shù),其實質(zhì)就是數(shù)字轉(zhuǎn)換成中文大寫,測試了一下,非常有趣,隨便輸個數(shù)字,就可以將其大寫打印出來,新手朋友們試一下吧2013-02-02iis6手工創(chuàng)建網(wǎng)站后無法運行php腳本的解決方法
下面小編就為大家?guī)硪黄猧is6手工創(chuàng)建網(wǎng)站后無法運行php腳本的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06php?overtrue/pinyin拓展實現(xiàn)漢字轉(zhuǎn)拼音
這篇文章主要為大家介紹了php?overtrue/pinyin拓展實現(xiàn)漢字轉(zhuǎn)拼音示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11