- 資訊首頁(yè) > 網(wǎng)絡(luò )安全 >
- laravel 服務(wù)容器的實(shí)現原理是什么
laravel 服務(wù)容器的實(shí)現原理是什么,很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細講解,有這方面需求的人可以來(lái)學(xué)習下,希望你能有所收獲。
服務(wù)容器是用來(lái)管理類(lèi)依賴(lài)與運行依賴(lài)注入的工具。Laravel框架中就是使用服務(wù)容器來(lái)實(shí)現 ** 控制反轉 ** 和 ** 依賴(lài)注入 **。
控制反轉(IoC) 就是說(shuō)把創(chuàng )建對象的** 控制權 進(jìn)行轉移,以前創(chuàng )建對象的主動(dòng)權和創(chuàng )建時(shí)機是由自己把控的,而現在這種權力轉移到第三方,也就是 Laravel ** 中的容器。
依賴(lài)注入(DI)則是幫助容器實(shí)現在運行中動(dòng)態(tài)的為對象提供提依賴(lài)的資源。
概念容易不太容易讓人理解,舉個(gè)栗子:
//我們構建一個(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è)人在遛狗,突然遇到了死對頭,他于是放狗咬人
$people = new People();
$people->putDog();在這個(gè)操作中,people類(lèi)要執行
putDog() 這個(gè)方法,需要依賴(lài)Dog類(lèi),一般我們像上面一樣,在people中利用構造函數來(lái)添加這個(gè)Dog依賴(lài)。如果使用控制反轉 依賴(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ò)構造參數聲明自己需要的 依賴(lài)類(lèi),由容器自動(dòng)注入。這樣就實(shí)現了程序的有效解耦,好處在這就不多說(shuō)了。## Laravel容器依賴(lài)注入的實(shí)現###### 實(shí)現原理需要了解的知識點(diǎn):> 閉包(匿名函數):匿名函數(Anonymous functions),也叫閉包函數(closures),允許 臨時(shí)創(chuàng )建一個(gè)沒(méi)有指定名稱(chēng)的函數> 反射:PHP 5 以上版本具有完整的反射 API,添加了對類(lèi)、接口、函數、方法和擴展進(jìn)行反向工程的能力。 此外,反射 API 提供了方法來(lái)取出函數、類(lèi)和方法中的文檔注釋###### 理解了閉包和反射的基本用法我們來(lái)看Laravel中是怎么實(shí)現容器的,下面代碼是我對laravel框架容器部分代碼的簡(jiǎn)化核心版:
lass Container
{
/**
* 容器綁定,用來(lái)裝提供的實(shí)例或者 提供實(shí)例的回調函數
* @var array
*/
public $building = [];
/** * 注冊一個(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"); }//注冊一個(gè)共享的綁定 單例public function singleton($abstract, $concrete, $shared = true){ $this->bind($abstract, $concrete, $shared); }/** * 默認生成實(shí)例的回調閉包 * * @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; }/** * 獲取綁定的回調函數 */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; }/** * 根據實(shí)例具體名稱(chēng)實(shí)例具體對象 */public function build($concrete){ if($concrete instanceof Closure){ return $concrete($this); } //創(chuàng )建反射對象 $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ò)反射解決參數依賴(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('出錯'); }//通過(guò)容器解決依賴(lài)public function resolvedClass(ReflectionParameter $parameter){ return $this->make($parameter->getClass()->name); }
}
```
接著(zhù)上面遛狗的例子://實(shí)例化容器類(lèi) $app = new Container(); //向容器中填充Dog $app->bind('Dog','App\Dog'); //填充People $app->bind('People', 'App\People'); //通過(guò)容器實(shí)現依賴(lài)注入,完成類(lèi)的實(shí)例化; $people = $app->make('People'); //調用方法 echo $people->putDog();
上面示例中我們先實(shí)例化容器類(lèi),然后使用bind()
方法 綁定接口和 生成相應的實(shí)例的閉包函數。然后使用make()
函數生成實(shí)例對象,在make()
中會(huì )調用 isBuildable($concrete, $abstract)
來(lái)判斷 給定的服務(wù)實(shí)體($concrete
參數)是否可以創(chuàng )建,可以創(chuàng )建 就會(huì )調用 build($concrete)
函數 ,build($concrete)
函數會(huì )判斷傳的參數是 是** 閉包 還是 具體類(lèi)名 **,如果是閉包則直接運行,如果是具體類(lèi)名的話(huà),則通過(guò)反射獲取該類(lèi)的構造函數所需的依賴(lài),完成實(shí)例化。
** 重點(diǎn)理解 下面這幾個(gè)函數中 反射的用法,應該就很好理解了 **build($concrete) getDependencies(array $dependencies) resolvedNonClass(ReflectionParameter $parameter) resolvedClass(ReflectionParameter $parameter)
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站