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