<輸入的最好方式就是輸出>,本著學(xué)習(xí)的態(tài)度表達一下自己淺顯的理解住练。IOC(Inversion of Control)愁拭,即控制反轉(zhuǎn)岭埠,是面向?qū)ο笾械囊环N設(shè)計原則蔚鸥。下面我將簡單介紹IOC的作用和實現(xiàn)原理止喷,最后用具體的示例應(yīng)用來幫助加深理解弹谁。
1、IOC的作用
IOC可以作為依賴對象的統(tǒng)一管理者沟于,從而降低代碼的耦合性旷太,提升程序的可維護性供璧。
2冻记、實現(xiàn)原理
IOC作為管理依賴的容器,涉及的相關(guān)技術(shù)是反射和依賴注入吕嘀。
下面將簡單介紹PHP反射和依賴注入。
-
PHP反射
簡單概括就是對象的自省能力趁曼,對象通過反射獲取其類的信息棕洋。
示例代碼:
$node = new LinkNode();//實例化對象
$nodeClass = new ReflectionClass($node);//通過對象獲取其反射類
//$nodeClass = new ReflectionClass('App\Service\LinkNode')//通過類名獲取反射類
$properties = $nodeClass->getProperties();//獲取類的所有屬性
$methods = $nodeClass->getMethods();//獲取類的所有方法
$constructorParamClass = $nodeClass->getConstructor()->getParameters()[0]->getClass()->name;//首個構(gòu)造函數(shù)參數(shù)類名
-
依賴注入
DI(dependency injection)摄悯,即依賴注入愧捕,它是IOC的實現(xiàn)方式之一。下面將介紹PHP-DI相關(guān)原理(參考文檔:https://php-di.org/doc/getting-started.html)瘪阁,以下是文檔部分內(nèi)容:
1-php-di
上圖代碼塊介紹了依賴注入的作用管跺,例子中UserManager類需要依賴Mailer類禾进。通過注入的方式可避免手動實例化依賴對象泻云,即調(diào)用UserManager時可以不用手動實例化依賴對象壶愤。
標(biāo)紅的兩塊則是IOC容器實現(xiàn)依賴注入的技術(shù),autowiring(自動裝載)和PHP's Reflection classes(PHP反射類)娇哆。autowiring可以掃描代碼找到類的構(gòu)造函數(shù)所需要的參數(shù)是什么(本例中是Mailer對象)碍讨,php-di通過php反射類即可找到Mailer類并實例化對象蒙秒。php反射類前面已經(jīng)介紹過了晕讲,下面介紹下autowiring的原理。
上圖第一個紅框表明痊班,容器可以通過自動裝載自動創(chuàng)建和注入依賴涤伐;第二個紅框表示注入的過程等同于先實例化對象凝果,再傳遞給構(gòu)造函數(shù)的參數(shù)器净。另外文檔還指出当凡,構(gòu)造函數(shù)的參數(shù)必須要有類型提示才能實現(xiàn)注入。
php-di注入的方式其實不止autowiring這一種,總共有三種:autowiring(自動裝載)欧瘪、annotation(注解)匙赞、PHP definitions(PHP定義)涌庭,感興趣的小伙伴可以自行查閱文檔相關(guān)內(nèi)容。
總結(jié):IOC容器通過依賴注入的方式幫我們管理類的依賴關(guān)系拴魄,而不需要我們手動去管理依賴(實例化依賴對象)匹中。本文的php依賴注入利用php反射找到依賴信息顶捷,autowiring自動加載實現(xiàn)構(gòu)造參數(shù)的注入屎篱。
3、示例應(yīng)用(Laravel)
紙上得來終覺淺践付,簡單介紹完IOC容器的實現(xiàn)原理荔仁,現(xiàn)在以laravel為例具體實踐應(yīng)用一下芽死,有助于加深理解关贵。示例主要涉及兩個層面揖曾,一個將類的依賴關(guān)系綁定到容器;另一個是從容器中解析類练链。
Laravel官方文檔
英文版:https://laravel.com/docs/8.x/container#when-to-use-the-container
中文版:https://learnku.com/docs/laravel/8.5/container/10365#120d42
- IOC容器綁定類的依賴關(guān)系
在這個例子中,Transistor是要綁定的類错妖,它的依賴類是PodcastParser暂氯。如果 PodcastParser類自身也存在依賴痴施,容器會根據(jù)它所綁定的依賴關(guān)系擎厢,遞歸地 解析相應(yīng)的依賴。use App\Services\Transistor; use App\Services\PodcastParser; $this->app->bind(Transistor::class, function ($app) { return new Transistor($app->make(PodcastParser::class)); });
需要注意的是晾剖,如果PodcastParser沒有在容器中綁定過锉矢,使用容器解析作為依賴會報錯,即不能使用$app->make(PodcastParser::class)齿尽,而應(yīng)該使用new PodcastParser()
- IOC容器的使用
IOC容器的使用可以分為兩步沽损,依賴注入和make解析獲取對象;
1 依賴注入分為構(gòu)造函數(shù)注入和set函數(shù)注入循头。
2 Laravel中解析容器對象绵估,可以使用助手函數(shù)從容器中解析獲妊捉:app()->make(PodcastParser::class);
【另外国裳,Laravel中的Facade門面類(靜態(tài)代理類)本質(zhì)也是通過容器解析對象形入;指定類要綁定別名至容器缝左,同時對應(yīng)的靜態(tài)類要繼承Facade類并重寫getFacadeAccessor方法指定綁定別名,之后就能使用門面類實例對象了耳舅。】
以上只是簡單介紹了一下Laravel容器的依賴綁定和使用,方便理解IOC容器的運作過程。
實際上綁定過程還涉及到Laravel的核心<服務(wù)提供者>箩言,我們需要在提供者的register注冊方法中綁定相關(guān)依賴;綁定的類型也有很多種,可分為單例綁定(每次解析都是單例對象),接口綁定(自動解析注入的接口為指定實現(xiàn)類)等等老赤,這邊暫時不展開,感興趣的小伙伴可以自行查閱文檔。