小編給大家分享一下Laravel—IOC容器是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
成都創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)整合營(yíng)銷推廣、網(wǎng)站重做改版、臨桂網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5頁(yè)面制作、商城開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為臨桂等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
IOC( inversion of controller )叫做控制反轉(zhuǎn)模式,也可以稱為(dependency injection ) 依賴注入模式。要理解依賴注入的概念我們先理解下什么依賴
//支付寶支付 class Alipay { public function __construct(){} public function pay() { echo 'pay bill by alipay'; } } //微信支付 class Wechatpay { public function __construct(){} public function pay() { echo 'pay bill by wechatpay'; } } //銀聯(lián)支付 class Unionpay{ public function __construct(){} public function pay() { echo 'pay bill by unionpay'; } } //支付賬單 class PayBill { private $payMethod; public function __construct( ) { $this->payMethod= new Alipay (); } public function payMyBill() { $this->payMethod->pay(); } } $pb = new PayBill (); $pb->payMyBill();
通過(guò)上面的代碼我們知道,當(dāng)我們創(chuàng)建一個(gè)class PayBill 的實(shí)例的時(shí)候, PayBill的構(gòu)造函數(shù)里面有{ $this->payMethod= new Alipay (); }, 也就是實(shí)例化了一個(gè)class Alipay . 這個(gè)時(shí)候依賴就產(chǎn)生了, 這里可以理解為當(dāng)我想用支付寶支付的時(shí)候, 那我首先要獲取到一個(gè)支付寶的實(shí)例,或者理解為獲取支付寶的功能支持. 當(dāng)用我們完 new 關(guān)鍵字的時(shí)候, 依賴其實(shí)已經(jīng)解決了,因?yàn)槲覀儷@取了Alipay 的實(shí)例.
其實(shí)在我知道ioc概念之前,我的代碼中大部分都是這種模式 ~ _ ~ . 這種有什么問題呢, 簡(jiǎn)單來(lái)說(shuō), 比如當(dāng)我想用的不是支付寶而是微信的時(shí)候怎么辦, 你能做的就是修改Payment 的構(gòu)造函數(shù)的代碼,實(shí)例化一個(gè)微信支付Wechatpay.
如果我們的程序不是很大的時(shí)候可能還感覺不出什么,但是當(dāng)你的代碼非常復(fù)雜,龐大的時(shí)候,如果我們的需求經(jīng)常改變,那么修改代碼就變的非常麻煩了。所以ioc 的思想就是不要在 class Payment 里面用new 的方式去實(shí)例化解決依賴, 而且轉(zhuǎn)為由外部來(lái)負(fù)責(zé),簡(jiǎn)單一點(diǎn)就是內(nèi)部沒有new 的這個(gè)步驟,通過(guò)依賴注入的方式同樣的能獲取到支付的實(shí)例.
依賴我們知道了是什么意思,那依賴注入又是什么意思呢,我們把上面的代碼拓展一下
//支付類接口 interface Pay { public function pay(); } //支付寶支付 class Alipay implements Pay { public function __construct(){} public function pay() { echo 'pay bill by alipay'; } } //微信支付 class Wechatpay implements Pay { public function __construct(){} public function pay() { echo 'pay bill by wechatpay'; } } //銀聯(lián)支付 class Unionpay implements Pay { public function __construct(){} public function pay() { echo 'pay bill by unionpay'; } } //付款 class PayBill { private $payMethod; public function __construct( Pay $payMethod) { $this->payMethod= $payMethod; } public function payMyBill() { $this->payMethod->pay(); } } //生成依賴 $payMethod = new Alipay(); //注入依賴 $pb = new PayBill( $payMethod ); $pb->payMyBill();
上面的代碼中,跟之前的比較的話,我們加入一個(gè)Pay 接口, 然后所有的支付方式都繼承了這個(gè)接口并且實(shí)現(xiàn)了pay 這個(gè)功能. 可能大家會(huì)問為什么要用接口,這個(gè)我們稍后會(huì)講到.
當(dāng)我們實(shí)例化PayBill的之前, 我們首先是實(shí)例化了一個(gè)Alipay,這個(gè)步驟就是生成了依賴了,然后我們需要把這個(gè)依賴注入到PayBill 的實(shí)例當(dāng)中,通過(guò)代碼我們可以看到 { $pb = new PayBill( payMethod ); }, 我們是通過(guò)了構(gòu)造函數(shù)把這個(gè)依賴注入了PayBill 里面. 這樣一來(lái) $pb 這個(gè)PayBill 的實(shí)例就有了支付寶支付的能力了.
把class Alipay 的實(shí)例通過(guò)constructor注入的方式去實(shí)例化一個(gè) class PayBill. 在這里我們的注入是手動(dòng)注入, 不是自動(dòng)的. 而Laravel 框架實(shí)現(xiàn)則是自動(dòng)注入.
在介紹IOC 的容器之前我們先來(lái)理解下反射的概念(reflection),因?yàn)镮OC 容器也是要通過(guò)反射來(lái)實(shí)現(xiàn)的.從網(wǎng)上抄了一段來(lái)解釋反射是什么意思
“反射它指在PHP運(yùn)行狀態(tài)中,擴(kuò)展分析PHP程序,導(dǎo)出或提取出關(guān)于類、方法、屬性、參數(shù)等的詳細(xì)信息,包括注釋。這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為反射API。反射是操縱面向?qū)ο蠓缎椭性P偷腁PI,其功能十分強(qiáng)大,可幫助我們構(gòu)建復(fù)雜,可擴(kuò)展的應(yīng)用。其用途如:自動(dòng)加載插件,自動(dòng)生成文檔,甚至可用來(lái)擴(kuò)充PHP語(yǔ)言”
舉個(gè)簡(jiǎn)單的例子
class B{ } class A { public function __construct(B $args) { } public function dosomething() { echo 'Hello world'; } } //建立class A 的反射 $reflection = new ReflectionClass('A'); $b = new B(); //獲取class A 的實(shí)例 $instance = $reflection ->newInstanceArgs( [ $b ]); $instance->dosomething(); //輸出 ‘Hellow World’ $constructor = $reflection->getConstructor();//獲取class A 的構(gòu)造函數(shù) $dependencies = $constructor->getParameters();//獲取class A 的依賴類 dump($constructor); dump($dependencies);
dump 的得到的$constructor 和 $dependencies 結(jié)果如下
//constructor ReflectionMethod {#351 +name: "__construct" +class: "A" parameters: array:1 [] extra: array:3 [] modifiers: "public" } //$dependencies array:1 [ 0 => ReflectionParameter {#352 +name: "args" position: 0 typeHint: "B" } ]
通過(guò)上面的代碼我們可以獲取到 class A 的構(gòu)造函數(shù),還有構(gòu)造函數(shù)依賴的類,這個(gè)地方我們依賴一個(gè)名字為 ‘a(chǎn)rgs’ 的量,而且通過(guò)TypeHint可以知道他是類型為 Class B; 反射機(jī)制可以讓我去解析一個(gè)類,能過(guò)獲取一個(gè)類里面的屬性,方法 ,構(gòu)造函數(shù), 構(gòu)造函數(shù)需要的參數(shù)。 有個(gè)了這個(gè)才能實(shí)現(xiàn)Laravel 的IOC 容器.
接下來(lái)介紹一下Laravel 的IOC服務(wù)容器概念. 在laravel框架中, 服務(wù)容器是整個(gè)laravel的核心,它提供了整個(gè)系統(tǒng)功能及服務(wù)的配置, 調(diào)用. 容器按照字面上的理解就是裝東西的東西,比如冰箱, 當(dāng)我們需要冰箱里面的東西的時(shí)候直接從里面拿就行了. 服務(wù)容器也可以這樣理解, 當(dāng)程序開始運(yùn)行的時(shí)候,我們把我們需要的一些服務(wù)放到或者注冊(cè)到(bind)到容器里面,當(dāng)我需要的時(shí)候直接取出來(lái)(make)就行了. 上面提到的 bind 和 make 就是注冊(cè) 和 取出的 兩個(gè)動(dòng)作.
好了,說(shuō)了這么多,下面要上一段容器的代碼了. 下面這段代碼不是laravel 的源碼, 而是來(lái)自一本書《laravel 框架關(guān)鍵技術(shù)解析》. 這段代碼很好的還原了laravel 的服務(wù)容器的核心思想. 代碼有點(diǎn)長(zhǎng), 小伙伴們要耐心看. 當(dāng)然小伙伴完全可以試著運(yùn)行一下這段代碼,然后調(diào)試一下,這樣會(huì)更有助于理解.
<?php //容器類裝實(shí)例或提供實(shí)例的回調(diào)函數(shù) class Container { //用于裝提供實(shí)例的回調(diào)函數(shù),真正的容器還會(huì)裝實(shí)例等其他內(nèi)容 //從而實(shí)現(xiàn)單例等高級(jí)功能 protected $bindings = []; //綁定接口和生成相應(yīng)實(shí)例的回調(diào)函數(shù) public function bind($abstract, $concrete=null, $shared=false) { //如果提供的參數(shù)不是回調(diào)函數(shù),則產(chǎn)生默認(rèn)的回調(diào)函數(shù) if(!$concrete instanceof Closure) { $concrete = $this->getClosure($abstract, $concrete); } $this->bindings[$abstract] = compact('concrete', 'shared'); } //默認(rèn)生成實(shí)例的回調(diào)函數(shù) protected 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; } protected function isBuildable($concrete, $abstract) { return $concrete === $abstract || $concrete instanceof Closure; } //獲取綁定的回調(diào)函數(shù) protected function getConcrete($abstract) { if(!isset($this->bindings[$abstract])) { return $abstract; } return $this->bindings[$abstract]['concrete']; } //實(shí)例化對(duì)象 public function build($concrete) { if($concrete instanceof Closure) { return $concrete($this); } $reflector = new ReflectionClass($concrete); if(!$reflector->isInstantiable()) { echo $message = "Target [$concrete] is not instantiable"; } $constructor = $reflector->getConstructor(); if(is_null($constructor)) { return new $concrete; } $dependencies = $constructor->getParameters(); $instances = $this->getDependencies($dependencies); return $reflector->newInstanceArgs($instances); } //解決通過(guò)反射機(jī)制實(shí)例化對(duì)象時(shí)的依賴 protected function getDependencies($parameters) { $dependencies = []; foreach($parameters as $parameter) { $dependency = $parameter->getClass(); if(is_null($dependency)) { $dependencies[] = NULL; } else { $dependencies[] = $this->resolveClass($parameter); } } return (array)$dependencies; } protected function resolveClass(ReflectionParameter $parameter) { return $this->make($parameter->getClass()->name); } }
上面的代碼就生成了一個(gè)容器,下面是如何使用容器
$app = new Container(); $app->bind("Pay", "Alipay");//Pay 為接口, Alipay 是 class Alipay $app->bind("tryToPayMyBill", "PayBill"); //tryToPayMyBill可以當(dāng)做是Class PayBill 的服務(wù)別名 //通過(guò)字符解析,或得到了Class PayBill 的實(shí)例 $paybill = $app->make("tryToPayMyBill"); //因?yàn)橹耙呀?jīng)把Pay 接口綁定為了 Alipay,所以調(diào)用pay 方法的話會(huì)顯示 'pay bill by alipay ' $paybill->payMyBill();
當(dāng)我們實(shí)例化一個(gè)Container得到 $app 后, 我們就可以向其中填充東西了
$app->bind("Pay", "Alipay"); $app->bind("tryToPayMyBill", "PayBill");
當(dāng)執(zhí)行完這兩行綁定碼后, $app 里面的屬性 $bindings 就已經(jīng)有了array 值,是啥樣的呢,我們來(lái)看下
array:2 [ "App\Http\Controllers\Pay" => array:2 [ "concrete" => Closure {#355 class: "App\Http\Controllers\Container" this:Container{[#354](http://127.0.0.4/ioc#sf-dump-254248394-ref2354) …} parameters: array:1 [ "$c" => [] ] use: array:2 [ "$abstract" => "App\Http\Controllers\Pay" "$concrete" => "App\Http\Controllers\Alipay" ] file: "C:\project\test\app\Http\Controllers\IOCController.php" line: "119 to 122" } "shared" => false ] "tryToPayMyBill" => array:2 [ "concrete" => Closure {#359 class: "App\Http\Controllers\Container" this:Container{[#354](http://127.0.0.4/ioc#sf-dump-254248394-ref2354) …} parameters: array:1 [ "$c" => [] ] use: array:2 [ "$abstract" => "tryToPayMyBill" "$concrete" => "\App\Http\Controllers\PayBill" ] file: "C:\project\test\app\Http\Controllers\IOCController.php" line: "119 to 122" } "shared" => false ] ]
當(dāng)執(zhí)行 $paybill = $app->make(“tryToPayMyBill”); 的時(shí)候, 程序就會(huì)用make方法通過(guò)閉包函數(shù)的回調(diào)開始解析了.
解析’tryToPayBill’ 這個(gè)字符串, 程序通過(guò)閉包函數(shù) 和build方法會(huì)得到 ‘PayBill’ 這個(gè)字符串,該字符串保存在$concrete 上. 這個(gè)是第一步. 然后程序還會(huì)以類似于遞歸方式 將$concrete 傳入 build() 方法. 這個(gè)時(shí)候build里面就獲取了$concrete = ‘PayBill’. 這個(gè)時(shí)候反射就派上了用場(chǎng), 大家有沒有發(fā)現(xiàn),PayBill 不就是 class PayBill 嗎? 然后在通過(guò)反射的方法ReflectionClass(‘PayBill’) 獲取PayBill 的實(shí)例. 之后通過(guò)getConstructor(),和getParameters() 等方法知道了 Class PayBill 和 接口Pay 存在依賴
//$constructor = $reflector->getConstructor(); ReflectionMethod {#374 +name: "__construct" +class: "App\Http\Controllers\PayBill" parameters: array:1 [ "$payMethod" => ReflectionParameter {#371 +name: "payMethod" position: 0 typeHint: "App\Http\Controllers\Pay" } ] extra: array:3 [ "file" => "C:\project\test\app\Http\Controllers\IOCController.php" "line" => "83 to 86" "isUserDefined" => true ] modifiers: "public" } //$dependencies = $constructor->getParameters(); array:1 [ 0 => ReflectionParameter {#370 +name: "payMethod" position: 0 typeHint: "App\Http\Controllers\Pay" } ]
接著,我們知道了有’Pay’這個(gè)依賴之后呢,我們要做的就是解決這個(gè)依賴,通過(guò) getDependencies($parameters), 和 resolveClass(ReflectionParameter $parameter) ,還有之前的綁定$app->bind(“Pay”, “Alipay”); 在build 一次的時(shí)候,通過(guò) return new $concrete;到這里我們得到了這個(gè)Alipay 的實(shí)例
if(is_null($constructor)) { return new $concrete; }
到這里我們總算結(jié)局了這個(gè)依賴, 這個(gè)依賴的結(jié)果就是實(shí)例化了一個(gè) Alipay. 到這里還沒結(jié)束
$instances = $this->getDependencies($dependencies);
上面的$instances 數(shù)組只有一個(gè)element 那就是 Alipay 實(shí)例
array:1 [0 =>Alipay {#380} ]
最終通過(guò) newInstanceArgs() 方法, 我們獲取到了 PayBill 的實(shí)例。
return $reflector->newInstanceArgs($instances);
到這里整個(gè)流程就結(jié)束了, 我們通過(guò) bind 方式綁定了一些依賴關(guān)系, 然后通過(guò)make 方法 獲取到到我們想要的實(shí)例. 在make中有牽扯到了閉包函數(shù),反射等概念.
好了,當(dāng)我們把容器的概念理解了之后,我們就可以理解下為什么要用接口這個(gè)問題了. 如果說(shuō)我不想用支付寶支付,我要用微信支付怎么辦,too easy.
$app->bind("Pay", "Wechatpay"); $app->bind("tryToPayMyBill", "PayBill"); $paybill = $app->make("tryToPayMyBill"); $paybill->payMyBill();
是不是很簡(jiǎn)單呢, 只要把綁定從’Alipay’ 改成 ‘Wechatpay’ 就行了,其他的都不用改. 這就是為什么我們要用接口. 只要你的支付方式繼承了pay 這個(gè)接口,并且實(shí)現(xiàn)pay 這個(gè)方法,我們就能夠通過(guò)綁定正常的使用. 這樣我們的程序就非常容易被拓展,因?yàn)橐院罂赡軙?huì)出現(xiàn)成百上千種的支付方式.
好了,到這里不知道小伙伴有沒有理解呢,我建議大家可以試著運(yùn)行下這些代碼, 這樣理解起來(lái)會(huì)更快.同時(shí)推薦大家去看看 《laravel 框架關(guān)鍵技術(shù)解析》這本書,寫的還是不錯(cuò)的.
以上是“Laravel—IOC容器是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
新聞標(biāo)題:Laravel—IOC容器是什么
瀏覽路徑:http://sd-ha.com/article20/jiigco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、小程序開發(fā)、網(wǎng)站維護(hù)、營(yíng)銷型網(wǎng)站建設(shè)、微信小程序、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)