摘要:框架中就是使用服務(wù)容器來(lái)實(shí)現(xiàn)控制反轉(zhuǎn)和依賴(lài)注入。容器依賴(lài)注入的實(shí)現(xiàn)實(shí)現(xiàn)原理需要了解的知識(shí)點(diǎn)閉包匿名函數(shù)匿名函數(shù),也叫閉包函數(shù),允許臨時(shí)創(chuàng)建一個(gè)沒(méi)有指定名稱(chēng)的函數(shù)反射以上版本具有完整的反射,添加了對(duì)類(lèi)接口函數(shù)方法和擴(kuò)展進(jìn)行反向工程的能力。
前言
通過(guò)實(shí)現(xiàn)laravel 框架功能,以便深入理解laravel框架的先進(jìn)思想。
什么是服務(wù)容器什么是控制反轉(zhuǎn)(IoC)和依賴(lài)注入(DI)服務(wù)容器是用來(lái)管理類(lèi)依賴(lài)與運(yùn)行依賴(lài)注入的工具。Laravel框架中就是使用服務(wù)容器來(lái)實(shí)現(xiàn) 控制反轉(zhuǎn) 和 依賴(lài)注入 。
控制反轉(zhuǎn)(IoC) 就是說(shuō)把創(chuàng)建對(duì)象的 控制權(quán) 進(jìn)行轉(zhuǎn)移,以前創(chuàng)建對(duì)象的主動(dòng)權(quán)和創(chuàng)建時(shí)機(jī)是由自己把控的,而現(xiàn)在這種權(quán)力轉(zhuǎn)移到第三方,也就是 Laravel 中的容器。
依賴(lài)注入(DI)則是幫助容器實(shí)現(xiàn)在運(yùn)行中動(dòng)態(tài)的為對(duì)象提供提依賴(lài)的資源。
概念容易不太容易讓人理解,舉個(gè)栗子:
//我們構(gòu)建一個(gè)人的類(lèi)和一個(gè)狗的類(lèi) class People { public $dog = null; public function __construct() { $this->dog = new Dog(); } public function putDog(){ return $this->dog->dogCall(); } } class Dog{ public function dogCall(){ return "汪汪汪"; } }
這個(gè)人在遛狗,突然遇到了死對(duì)頭,他于是放狗咬人
$people = new People(); $people->putDog();
在這個(gè)操作中,people類(lèi)要執(zhí)行 putDog() 這個(gè)方法,需要依賴(lài)Dog類(lèi),一般我們像上面一樣,在people中利用構(gòu)造函數(shù)來(lái)添加這個(gè)Dog依賴(lài)。如果使用控制反轉(zhuǎn) 依賴(lài)注入則是這個(gè)樣子
class People { public $dog = null; public function __construct(Dog $Dog) { $this->dog = $dog; } public function putDog(){ return $this->dog->dogCall(); } }
People類(lèi)通過(guò)構(gòu)造參數(shù)聲明自己需要的 依賴(lài)類(lèi),由容器自動(dòng)注入。這樣就實(shí)現(xiàn)了程序的有效解耦,好處在這就不多說(shuō)了。
Laravel容器依賴(lài)注入的實(shí)現(xiàn)閉包(匿名函數(shù)):
匿名函數(shù)(Anonymous functions),也叫閉包函數(shù)(closures),允許 臨時(shí)創(chuàng)建一個(gè)沒(méi)有指定名稱(chēng)的函數(shù)
反射:PHP 5 以上版本具有完整的反射 API,添加了對(duì)類(lèi)、接口、函數(shù)、方法和擴(kuò)展進(jìn)行反向工程的能力。 此外,反射 API 提供了方法來(lái)取出函數(shù)、類(lèi)和方法中的文檔注釋
lass Container { /** * 容器綁定,用來(lái)裝提供的實(shí)例或者 提供實(shí)例的回調(diào)函數(shù) * @var array */ public $building = []; /** * 注冊(cè)一個(gè)綁定到容器 */ public function bind($abstract, $concrete = null, $shared = false) { if(is_null($concrete)){ $concrete = $abstract; } if(!$concrete instanceOf Closure){ $concrete = $this->getClosure($abstract, $concrete); } $this->building[$abstract] = compact("concrete", "shared"); } //注冊(cè)一個(gè)共享的綁定 單例 public function singleton($abstract, $concrete, $shared = true){ $this->bind($abstract, $concrete, $shared); } /** * 默認(rèn)生成實(shí)例的回調(diào)閉包 * * @param $abstract * @param $concrete * @return Closure */ public function getClosure($abstract, $concrete) { return function($c) use($abstract, $concrete){ $method = ($abstract == $concrete)? "build" : "make"; return $c->$method($concrete); }; } /** * 生成實(shí)例 */ public function make($abstract) { $concrete = $this->getConcrete($abstract); if($this->isBuildable($concrete, $abstract)){ $object = $this->build($concrete); }else{ $object = $this->make($concrete); } return $object; } /** * 獲取綁定的回調(diào)函數(shù) */ public function getConcrete($abstract) { if(! isset($this->building[$abstract])){ return $abstract; } return $this->building[$abstract]["concrete"]; } /** * 判斷 是否 可以創(chuàng)建服務(wù)實(shí)體 */ public function isBuildable($concrete, $abstract) { return $concrete === $abstract || $concrete instanceof Closure; } /** * 根據(jù)實(shí)例具體名稱(chēng)實(shí)例具體對(duì)象 */ public function build($concrete) { if($concrete instanceof Closure){ return $concrete($this); } //創(chuàng)建反射對(duì)象 $reflector = new ReflectionClass($concrete); if( ! $reflector->isInstantiable()){ //拋出異常 throw new Exception("無(wú)法實(shí)例化"); } $constructor = $reflector->getConstructor(); if(is_null($constructor)){ return new $concrete; } $dependencies = $constructor->getParameters(); $instance = $this->getDependencies($dependencies); return $reflector->newInstanceArgs($instance); } //通過(guò)反射解決參數(shù)依賴(lài) public function getDependencies(array $dependencies) { $results = []; foreach( $dependencies as $dependency ){ $results[] = is_null($dependency->getClass()) ?$this->resolvedNonClass($dependency) :$this->resolvedClass($dependency); } return $results; } //解決一個(gè)沒(méi)有類(lèi)型提示依賴(lài) public function resolvedNonClass(ReflectionParameter $parameter) { if($parameter->isDefaultValueAvailable()){ return $parameter->getDefaultValue(); } throw new Exception("出錯(cuò)"); } //通過(guò)容器解決依賴(lài) public function resolvedClass(ReflectionParameter $parameter) { return $this->make($parameter->getClass()->name); } }容器的工作流程
接著上面遛狗的例子:
//實(shí)例化容器類(lèi) $app = new Container(); //向容器中填充Dog $app->bind("Dog","AppDog"); //填充People $app->bind("People", "AppPeople"); //通過(guò)容器實(shí)現(xiàn)依賴(lài)注入,完成類(lèi)的實(shí)例化; $people = $app->make("People"); //調(diào)用方法 echo $people->putDog();
上面示例中我們先實(shí)例化容器類(lèi),然后使用 bind() 方法 綁定接口和 生成相應(yīng)的實(shí)例的閉包函數(shù)。然后使用 make() 函數(shù)生成實(shí)例對(duì)象,在 make() 中會(huì)調(diào)用 isBuildable($concrete, $abstract) 來(lái)判斷 給定的服務(wù)實(shí)體( $concrete 參數(shù))是否可以創(chuàng)建,可以創(chuàng)建 就會(huì)調(diào)用 build($concrete) 函數(shù) , build($concrete) 函數(shù)會(huì)判斷傳的參數(shù)是 是 閉包 還是 具體類(lèi)名 ,如果是閉包則直接運(yùn)行,如果是具體類(lèi)名的話(huà),則通過(guò)反射獲取該類(lèi)的構(gòu)造函數(shù)所需的依賴(lài),完成實(shí)例化。
重點(diǎn)理解 下面這幾個(gè)函數(shù)中 反射的用法,應(yīng)該就很好理解了
build($concrete) getDependencies(array $dependencies) resolvedNonClass(ReflectionParameter $parameter) resolvedClass(ReflectionParameter $parameter)最后
IoC 理解起來(lái)是有點(diǎn)難度,可能文中描述讓你感覺(jué)不是很清楚,可以將文中代碼 在php中用debug觀察 運(yùn)行狀態(tài)。
理解了容器的具體實(shí)現(xiàn)原理,再去看Laravel中的相關(guān)實(shí)現(xiàn),就會(huì)感覺(jué)豁然開(kāi)朗。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/22623.html
摘要:劃下重點(diǎn),服務(wù)容器是用于管理類(lèi)的依賴(lài)和執(zhí)行依賴(lài)注入的工具。類(lèi)的實(shí)例化及其依賴(lài)的注入,完全由服務(wù)容器自動(dòng)的去完成。 本文首發(fā)于 深入剖析 Laravel 服務(wù)容器,轉(zhuǎn)載請(qǐng)注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請(qǐng)求,又是如何生成響應(yīng)并最終呈現(xiàn)給用戶(hù)的工作原理。 本章將帶領(lǐng)大...
摘要:服務(wù)提供者啟動(dòng)原理之前我們有學(xué)習(xí)深度挖掘生命周期和深入剖析服務(wù)容器,今天我們將學(xué)習(xí)服務(wù)提供者。的所有核心服務(wù)都是通過(guò)服務(wù)提供者進(jìn)行引導(dǎo)啟動(dòng)的,所以想深入了解那么研究服務(wù)提供者的原理是個(gè)繞不開(kāi)的話(huà)題。 本文首發(fā)于 深入剖析 Laravel 服務(wù)提供者實(shí)現(xiàn)原理,轉(zhuǎn)載請(qǐng)注明出處。 今天我們將學(xué)習(xí) Laravel 框架另外一個(gè)核心內(nèi)容「服務(wù)提供者(Service Provider)」。服務(wù)提供...
摘要:如何實(shí)現(xiàn)持久化持久化,將在內(nèi)存中的的狀態(tài)保存到硬盤(pán)中,相當(dāng)于備份數(shù)據(jù)庫(kù)狀態(tài)。相當(dāng)于備份數(shù)據(jù)庫(kù)接收到的命令,所有被寫(xiě)入的命令都是以的協(xié)議格式來(lái)保存的。 最近社區(qū)里面有一篇文章引起了最多程序猿的關(guān)注,Laravel、PHPer 面試可能會(huì)遇到的問(wèn)題,看評(píng)論區(qū)不少小伙伴們被難倒,對(duì)于一些問(wèn)題同樣難倒了我(其實(shí)有很多啦),趁著周末有空,又總結(jié)梳理了一遍,順便來(lái)答一波題。由于個(gè)人技術(shù)水平有限,答...
閱讀 3092·2023-04-26 00:53
閱讀 3543·2021-11-19 09:58
閱讀 1705·2021-09-29 09:35
閱讀 3293·2021-09-28 09:46
閱讀 3873·2021-09-22 15:38
閱讀 2700·2019-08-30 15:55
閱讀 3020·2019-08-23 14:10
閱讀 3835·2019-08-22 18:17