摘要:在本篇,我嘗試用另一種方式實(shí)現(xiàn)。自動注入可以簡單理解為可以復(fù)用的方法,下面來看看怎么用來實(shí)現(xiàn)自動注入。
這里先假設(shè)一個場景:
有一個工廠(Factory),需要工人(Worker) 使用某個機(jī)器(Machine)來生產(chǎn)某種產(chǎn)品
即有這樣的依賴關(guān)系: Factory --> Worker --> Machine
不使用注入代碼大概是這樣子:
class Machine{ function run(){ echo "機(jī)器開動"; } } class Worker { function work(){ echo "工人開動機(jī)器 -> "; $machine = new Machine(); $machine -> run(); } } class Factory{ function produce(){ echo "工廠叫工人開工 -> "; $worker = new Worker(); $worker -> work(); } } $factory = new Factory(); $factory -> produce();
可以看出來,這里所依賴的對象都由類自己在內(nèi)部實(shí)例化,是一種強(qiáng)耦合,不利于測試和維護(hù)。比如我現(xiàn)在要改成另一種工人來生產(chǎn),那就要改工廠內(nèi)部,這是不合理的。
手工注入所謂的注入,就是將類所依賴的對象的實(shí)例化操作放在類外面,同時使用Interface來作出約束:
Interface Machine{ public function run(); } Interface Worker{ public function work(); } class Machine1 implements Machine{ function run(){ echo "機(jī)器 1 開動"; } } class Machine2 implements Machine{ function run(){ echo "機(jī)器 2 開動"; } } class Worker1 implements Worker{ private $machine; public function __construct(Machine $machine){ $this -> machine = $machine; } function work(){ echo "工人 1 開動機(jī)器 -> "; $this -> machine -> run(); } } class Worker2 implements Worker{ private $machine; public function __construct(Machine $machine){ $this -> machine = $machine; } function work(){ echo "工人 2 開動機(jī)器 -> "; $this -> machine -> run(); } } class Factory{ private $worker; public function __construct(Worker $worker){ $this -> worker = $worker; } function produce(){ echo "工廠叫工人開工 -> "; $this -> worker -> work(); } } $machine = new Machine1(); $worker = new Worker2($machine); $factory = new Factory($worker); $factory -> produce();
可以看出來,這樣的好處是解耦。比如:可以由工人1開動機(jī)器2來生產(chǎn),也可以由工人2來開動機(jī)器1來生產(chǎn),以后也可以隨時用新的工人(只要他會work)、Worker也可以隨時換其它的機(jī)器(只要它會run)來生產(chǎn)。這種轉(zhuǎn)換都不需要修改工廠或工人的代碼。
那么問題來了,現(xiàn)在只是把實(shí)例化從里面移到了外面,但如果依賴的東西多了,也是很麻煩的,這就需要一個自動注入的機(jī)制,也就是平時經(jīng)常聽到的注入容器,常見的容器都是用到反射來實(shí)現(xiàn),而且要在構(gòu)造函數(shù)中聲明注入的類型,相對還是比較麻煩。
在本篇,我嘗試用另一種方式實(shí)現(xiàn)。
trait自動注入trait可以簡單理解為可以復(fù)用的方法,下面來看看怎么用trait來實(shí)現(xiàn)自動注入。
思路就是用trait來實(shí)現(xiàn)魔術(shù)方法__get,通過該方法來自動生成依賴的對象,先看完整代碼
trait DI{ private $map = ["Worker" => "Worker1","Machine"=>"Machine2"]; function __get($k){ if(preg_match("/^[A-Z]/", $k)) { $obj = new $this -> map[$k]; if($obj instanceof $k){ return $obj; }else{ exit("不符約定"); } } } } Interface Machine{ public function run(); } Interface Worker{ public function work(); } class Machine1 implements Machine{ function run(){ echo "機(jī)器 1 開動"; } } class Machine2 implements Machine{ function run(){ echo "機(jī)器 2 開動"; } } class Worker1 implements Worker{ use DI; function work(){ echo "工人 1 開動機(jī)器 -> "; $this -> Machine -> run(); } } class Worker2 implements Worker{ use DI; function work(){ echo "工人 2 開動機(jī)器 -> "; $this -> Machine -> run(); } } class Factory{ use DI; function produce(){ echo "工廠叫工人開工 -> "; $this -> Worker -> work(); } } $factory = new Factory(); $factory -> produce();
trait中的map用來演示實(shí)現(xiàn)類和接口的綁定關(guān)系,以便進(jìn)行類型約束,實(shí)際應(yīng)用時可以用配置或其它方式實(shí)現(xiàn).
類中要使用依賴注入時,需聲明use DI, 同時,注入的對象為首字母大寫(你也可以用其它規(guī)則,相應(yīng)的修改trait中的判斷)
當(dāng)然了,這只是一個很粗糙的演示,只實(shí)現(xiàn)了基本的自動注入,它還有很多問題,比如原來的類如果也有__get方法時,就會產(chǎn)生覆蓋。
有興趣的可以嘗試完善一下看能不能在項(xiàng)目中實(shí)際使用。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/28396.html
摘要:判斷是否存在構(gòu)造函數(shù),不存在直接實(shí)例化,存在則通過來獲取輸入函數(shù),并有相應(yīng)的方法解決依賴參數(shù)問題,實(shí)現(xiàn)依賴注入。 Laravel 框架關(guān)鍵技術(shù)解析·讀書筆記(一) 第一章 入口文件 請求訪問的入口文件,主要完成幾部分工作,分別是: 自動加載函數(shù)的添加 服務(wù)器實(shí)例化與服務(wù)注冊 路由加載 請求實(shí)例化與路由分發(fā) 相應(yīng)生成與發(fā)送 其中,自動加載函數(shù)用于包含引用文件,改文件是composer...
摘要:在閱讀文檔的時候看到一個類是以聲明的。是一種代碼復(fù)用技術(shù),為的單繼承限制提供了一套靈活的代碼復(fù)用機(jī)制。下面把的代碼做一個修改以上代碼會輸出??梢钥闯鰞?yōu)先級的順序?yàn)?,?dāng)前類的優(yōu)先級基類。 ??在閱讀laravel文檔的時候看到一個類 是以 Trait聲明的。平時在工作中從來沒有用過,于是就去看了下官方文檔。原來這個類早在php5.4.0就有了??上г陧?xiàng)目中從來沒有用過。 ??Trait看...
摘要:和組合的語義定義了一種減少復(fù)雜性的方式,避免傳統(tǒng)多繼承和類相關(guān)典型問題。隊(duì)列的目的是將耗時的任務(wù)延時處理,比如發(fā)送郵件,從而大幅度縮短請求和相應(yīng)的時間。同樣的道理,根據(jù)引入不同的來完成對應(yīng)的功能。 showImg(https://segmentfault.com/img/remote/1460000010868178); Trait 概念 在常規(guī)的 PHP 開發(fā)中,我們都習(xí)慣于先編寫一...
摘要:事件將通過添加關(guān)注來激活。自動注冊事件監(jiān)聽器通過使用,你可以自動注冊事件監(jiān)聽器,而不需要使用。你可以自由使用這個宏,或者創(chuàng)造你自己的語法以上例子可作對于方法可查看文檔測試測試下載測試存儲導(dǎo)出測試隊(duì)列導(dǎo)出 Basics 最簡單的導(dǎo)出方法是創(chuàng)建一個自定義的導(dǎo)出類, 這里我們使用發(fā)票導(dǎo)出作為示例. 在 App/Exports 下創(chuàng)建一個 InvoicesExport 類 namespace...
摘要:很多開發(fā)朋友都沒有弄清楚性狀。性狀有兩個作用表明類可以做什么像是接口提供模塊化實(shí)現(xiàn)像是類。注是不要自我重復(fù)的簡稱,表示不要在多個地方重復(fù)編寫相同的代碼,如果需要修改遵守這個原則編寫的代碼,只需要在一出修改,改動就能體現(xiàn)到其他地方。 很多PHP開發(fā)朋友都沒有弄清楚Trait(性狀)。這是PHP5.4.0引入的新概念,既像類又像接口。性狀是類的補(bǔ)分實(shí)現(xiàn)(即常量、屬性、方法),可以混入一個...
閱讀 4639·2021-11-19 09:59
閱讀 3510·2021-10-12 10:12
閱讀 2724·2021-09-22 15:25
閱讀 3406·2019-08-30 15:55
閱讀 1269·2019-08-29 11:27
閱讀 1548·2019-08-28 18:06
閱讀 2822·2019-08-26 13:41
閱讀 2635·2019-08-26 13:41