亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

Laravel服務容器(IocContainer)的解讀

2020-03-22 17:48:16
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了關于Laravel服務容器(IocContainer)的解讀,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

Laravel的核心是IocContainer, 文檔中稱其為“服務容器”,服務容器是一個用于管理類依賴和執行依賴注入的強大工具,Laravel中的功能模塊比如 Route、Eloquent ORM、Request、Response等等等等,實際上都是與核心無關的類模塊提供的,這些類從注冊到實例化,最終被我們所使用,其實都是 laravel 的服務容器負責的。

如果對服務容器是什么沒有清晰概念的話推薦一篇博文來了解一下服務容器的來龍去脈:laravel神奇的服務容器

服務容器中有兩個概念控制反轉(IOC)和依賴注入(DI):

依賴注入和控制反轉是對同一件事情的不同描述,它們描述的角度不同。依賴注入是從html' target='_blank'>應用程序的角度在描述,應用程序依賴容器創建并注入它所需要的外部資源。而控制反轉是從容器的角度在描述,容器控制應用程序,由容器反向的向應用程序注入應用程序所需要的外部資源。

在Laravel中框架把自帶的各種服務綁定到服務容器,我們也可以綁定自定義服務到容器。當應用程序需要使用某一個服務時,服務容器會講服務解析出來同時自動解決服務之間的依賴然后交給應用程序使用。

本篇就來探討一下Laravel中的服務綁定和解析是如何實現的

服務綁定

常用的綁定服務到容器的方法有instance, bind, singleton, alias。下面我們分別來看一下。

instance

將一個已存在的對象綁定到服務容器里,隨后通過名稱解析該服務時,容器將總返回這個綁定的實例。

$api = new HelpSpot/API(new HttpClient);$this- app- instance( HelpSpot/Api , $api);

會把對象注冊到服務容器的$instnces屬性里

[ HelpSpot/Api = $api//$api是API類的對象,這里簡寫了 ]
bind

綁定服務到服務容器

有三種綁定方式:

1.綁定自身$this- app- bind( HelpSpot/API , null);2.綁定閉包$this- app- bind( HelpSpot/API , function () { return new HelpSpot/API();});//閉包直接提供類實現方式$this- app- bind( HelpSpot/API , function ($app) { return new HelpSpot/API($app- make( HttpClient });//閉包返回需要依賴注入的類3. 綁定接口和實現$this- app- bind( Illuminate/Tests/Container/IContainerContractStub , Illuminate/Tests/Container/ContainerImplementationStub 

針對第一種情況,其實在bind方法內部會在綁定服務之前通過getClosure()為服務生成閉包,我們來看一下bind方法源碼。

public function bind($abstract, $concrete = null, $shared = false) $abstract = $this- normalize($abstract); $concrete = $this- normalize($concrete); //如果$abstract為數組類似[ Illuminate/ServiceName = service_alias ] //抽取別名 service_alias 并且注冊到$aliases[]中 //注意:數組綁定別名的方式在5.4中被移除,別名綁定請使用下面的alias方法 if (is_array($abstract)) { list($abstract, $alias) = $this- extractAlias($abstract); $this- alias($abstract, $alias); $this- dropStaleInstances($abstract); if (is_null($concrete)) { $concrete = $abstract; //如果只提供$abstract,則在這里為其生成concrete閉包 if (! $concrete instanceof Closure) { $concrete = $this- getClosure($abstract, $concrete); $this- bindings[$abstract] = compact( concrete , shared  if ($this- resolved($abstract)) { $this- rebound($abstract);
// $c 就是$container,即服務容器,會在回調時傳遞給這個變量 return function ($c, $parameters = []) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? build : make return $c- $method($concrete, $parameters);}

bind把服務注冊到服務容器的$bindings屬性里類似這樣:

$bindings = [ HelpSpot/API = [//閉包綁定 concrete = function ($app, $paramters = []) { return $app- build( HelpSpot/API  shared = false//如果是singleton綁定,這個值為true Illuminate/Tests/Container/IContainerContractStub = [//接口實現綁定 concrete = Illuminate/Tests/Container/ContainerImplementationStub , shared = false]
singleton
public function singleton($abstract, $concrete = null) $this- bind($abstract, $concrete, true);}

singleton 方法是bind方法的變種,綁定一個只需要解析一次的類或接口到容器,然后接下來對于容器的調用該服務將會返回同一個實例

alias

把服務和服務別名注冊到容器:

public function alias($abstract, $alias) $this- aliases[$alias] = $this- normalize($abstract);}

alias 方法在上面講bind方法里有用到過,它會把把服務別名和服務類的對應關系注冊到服務容器的$aliases屬性里。
例如:

$this- app- alias( /Illuminate/ServiceName , service_alias 

綁定完服務后在使用時就可以通過

$this- app- make( service_alias 

將服務對象解析出來,這樣make的時候就不用寫那些比較長的類名稱了,對make方法的使用體驗上有很大提升。

服務解析

make: 從服務容器中解析出服務對象,該方法接收你想要解析的類名或接口名作為參數

/** * Resolve the given type from the container. * @param string $abstract * @param array $parameters * @return mixedpublic function make($abstract, array $parameters = []) //getAlias方法會假定$abstract是綁定的別名,從$aliases找到映射的真實類型名 //如果沒有映射則$abstract即為真實類型名,將$abstract原樣返回 $abstract = $this- getAlias($this- normalize($abstract)); // 如果服務是通過instance()方式綁定的,就直接解析返回綁定的service if (isset($this- instances[$abstract])) { return $this- instances[$abstract]; // 獲取$abstract接口對應的$concrete(接口的實現) $concrete = $this- getConcrete($abstract); if ($this- isBuildable($concrete, $abstract)) { $object = $this- build($concrete, $parameters); } else { //如果時接口實現這種綁定方式,通過接口拿到實現后需要再make一次才能 //滿足isBuildable的條件 ($abstract === $concrete) $object = $this- make($concrete, $parameters); foreach ($this- getExtenders($abstract) as $extender) { $object = $extender($object, $this); //如果服務是以singleton方式注冊進來的則,把構建好的服務對象放到$instances里, //避免下次使用時重新構建 if ($this- isShared($abstract)) { $this- instances[$abstract] = $object; $this- fireResolvingCallbacks($abstract, $object); $this- resolved[$abstract] = true; return $object;protected function getConcrete($abstract) if (! is_null($concrete = $this- getContextualConcrete($abstract))) { return $concrete; // 如果是$abstract之前沒有注冊類實現到服務容器里,則服務容器會認為$abstract本身就是接口的類實現 if (! isset($this- bindings[$abstract])) { return $abstract; return $this- bindings[$abstract][ concrete protected function isBuildable($concrete, $abstract) return $concrete === $abstract || $concrete instanceof Closure;}

通過對make方法的梳理我們發現,build方法的職能是構建解析出來的服務的對象的,下面看一下構建對象的具體流程。(構建過程中用到了PHP類的反射來實現服務的依賴注入)

public function build($concrete, array $parameters = []) // 如果是閉包直接執行閉包并返回(對應閉包綁定) if ($concrete instanceof Closure) { return $concrete($this, $parameters); // 使用反射ReflectionClass來對實現類進行反向工程 $reflector = new ReflectionClass($concrete); // 如果不能實例化,這應該是接口或抽象類,再或者就是構造函數是private的 if (! $reflector- isInstantiable()) { if (! empty($this- buildStack)) { $previous = implode( , , $this- buildStack); $message = Target [$concrete] is not instantiable while building [$previous].  } else { $message = Target [$concrete] is not instantiable.  throw new BindingResolutionException($message); $this- buildStack[] = $concrete; // 獲取構造函數 $constructor = $reflector- getConstructor(); // 如果構造函數是空,說明沒有任何依賴,直接new返回 if (is_null($constructor)) { array_pop($this- buildStack); return new $concrete; // 獲取構造函數的依賴(形參),返回一組ReflectionParameter對象組成的數組表示每一個參數 $dependencies = $constructor- getParameters(); $parameters = $this- keyParametersByArgument( $dependencies, $parameters // 構建構造函數需要的依賴 $instances = $this- getDependencies( $dependencies, $parameters array_pop($this- buildStack); return $reflector- newInstanceArgs($instances);//獲取依賴protected function getDependencies(array $parameters, array $primitives = []) $dependencies = []; foreach ($parameters as $parameter) { $dependency = $parameter- getClass(); // 某一依賴值在$primitives中(即build方法的$parameters參數)已提供 // $parameter- name返回參數名 if (array_key_exists($parameter- name, $primitives)) { $dependencies[] = $primitives[$parameter- name]; elseif (is_null($dependency)) { // 參數的ReflectionClass為null,說明是基本類型,如 int , string  $dependencies[] = $this- resolveNonClass($parameter); } else { // 參數是一個類的對象, 則用resolveClass去把對象解析出來 $dependencies[] = $this- resolveClass($parameter); return $dependencies;//解析出依賴類的對象protected function resolveClass(ReflectionParameter $parameter) try { // $parameter- getClass()- name返回的是類名(參數在typehint里聲明的類型) // 然后遞歸繼續make(在make時發現依賴類還有其他依賴,那么會繼續make依賴的依賴 // 直到所有依賴都被解決了build才結束) return $this- make($parameter- getClass()- name); } catch (BindingResolutionException $e) { if ($parameter- isOptional()) { return $parameter- getDefaultValue(); throw $e;}

服務容器就是laravel的核心, 它通過依賴注入很好的替我們解決對象之間的相互依賴關系,而又通過控制反轉讓外部來來定義具體的行為(Route, Eloquent這些都是外部模塊,它們自己定義了行為規范,這些類從注冊到實例化給你使用才是服務容器負責的)。

一個類要被容器所能夠提取,必須要先注冊至這個容器。既然 laravel 稱這個容器叫做服務容器,那么我們需要某個服務,就得先注冊、綁定這個服務到容器,那么提供服務并綁定服務至容器的東西,就是服務提供器(ServiceProvider)。服務提供者主要分為兩個部分,register(注冊) 和 boot(引導、初始化)由于篇幅問題關于Laravel服務提供器的內容請看另一篇Laravel核心解讀--服務提供器(ServiceProvider)。

以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP !

相關推薦:

Laravel核心解讀Request

Laravel服務提供器(ServiceProvider)的解讀

以上就是Laravel服務容器(IocContainer)的解讀的詳細內容,PHP教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品国产色综合久久不卡98口| 国产精品成人av性教育| 国产精品成人品| 日韩中文理论片| www.日韩.com| 操91在线视频| 亚洲欧美一区二区三区四区| 欧美在线视频观看免费网站| 日韩免费高清在线观看| 成人在线中文字幕| 国产午夜精品美女视频明星a级| 91超碰caoporn97人人| 亚洲一区二区久久久久久久| 精品国产91久久久久久老师| 欧美性猛交xxx| 色午夜这里只有精品| 欧美交受高潮1| 深夜福利亚洲导航| 午夜伦理精品一区| 亚洲一级片在线看| 色婷婷亚洲mv天堂mv在影片| 亚洲精品电影网| 亚洲人成自拍网站| 欧美精品激情在线| 欧美精品免费播放| 亚洲国产99精品国自产| 日韩av免费在线| 精品露脸国产偷人在视频| 亚洲欧美日本伦理| 亚洲人成亚洲人成在线观看| 日韩成人高清在线| 国产精品海角社区在线观看| 精品丝袜一区二区三区| 国产丝袜一区二区| 一本色道久久88综合亚洲精品ⅰ| 日韩欧美在线字幕| 久久综合色88| 97国产精品免费视频| 91免费看片在线| 亚洲老头同性xxxxx| 亚洲日韩欧美视频一区| 夜夜嗨av一区二区三区免费区| 国产不卡视频在线| 欧美成人精品xxx| 日韩成人激情视频| 国产日韩在线亚洲字幕中文| 永久免费精品影视网站| 国产成人亚洲综合91精品| 欧美人与性动交a欧美精品| 亚洲有声小说3d| 欧美精品激情在线| 97香蕉超级碰碰久久免费软件| 日产日韩在线亚洲欧美| 精品少妇一区二区30p| 国产精品一区二区在线| 成人激情视频在线播放| 亚洲国产精品字幕| 欧美富婆性猛交| 亚洲一区二区少妇| 精品国产91久久久久久| 69久久夜色精品国产69乱青草| 亚洲r级在线观看| 久久天堂av综合合色| 欧美富婆性猛交| 国内精品国产三级国产在线专| 国产美女扒开尿口久久久| 日韩在线免费视频观看| 69影院欧美专区视频| 国产精品扒开腿做| 欧美亚洲成人xxx| 美乳少妇欧美精品| 992tv成人免费视频| 欧美大片免费观看在线观看网站推荐| 亚洲理论片在线观看| 欧美一级淫片aaaaaaa视频| 91久久在线观看| 亚洲午夜女主播在线直播| 不卡在线观看电视剧完整版| 国产精品吹潮在线观看| 91免费在线视频| 久久香蕉国产线看观看av| 久久99久久99精品免观看粉嫩| 欧美午夜视频在线观看| 色偷偷av一区二区三区| 国产精品久久久久77777| 成人午夜激情网| 亚洲丁香婷深爱综合| 亚洲精品短视频| 久久国产精品网站| 日韩在线资源网| 日韩中文字幕不卡视频| 91精品视频免费观看| 51午夜精品视频| 神马久久桃色视频| 国产精品美女网站| 日韩精品在线免费| 久久中文字幕视频| 国产国语刺激对白av不卡| 国产精品视频地址| 欧美成人午夜激情在线| 亚洲自拍偷拍第一页| 亚洲qvod图片区电影| 亚洲成av人片在线观看香蕉| 国产精品91久久久| 亚洲天堂第一页| 在线视频欧美性高潮| 国产美女久久久| 色综合老司机第九色激情| 日韩免费黄色av| 日韩欧美国产网站| 国产精品色悠悠| 国产免费一区二区三区在线能观看| 久久久久久久一| 亚洲精品久久久久久下一站| 日韩av手机在线| 国产第一区电影| 亚洲精美色品网站| 久久夜色撩人精品| 亚洲成人1234| 日本亚洲精品在线观看| 狠狠躁夜夜躁人人躁婷婷91| 91超碰中文字幕久久精品| 日本中文字幕不卡免费| 精品久久久久国产| 久久国产精品久久久久久久久久| 日韩视频免费在线| 91性高湖久久久久久久久_久久99| 欧美极品美女视频网站在线观看免费| 欧美亚洲日本黄色| 亚洲精品www| 亚洲精品久久久久中文字幕欢迎你| 国产精品18久久久久久麻辣| 日韩电影第一页| 国产丝袜一区视频在线观看| 2019中文字幕免费视频| 亚洲欧洲日产国码av系列天堂| 国产精品白嫩美女在线观看| 亚洲bt欧美bt日本bt| 日韩欧美在线播放| 欧美日韩国产中文精品字幕自在自线| 国语自产在线不卡| 亚洲美女福利视频网站| 国产精品久久久久久久久久久不卡| 91av网站在线播放| 日韩最新中文字幕电影免费看| 欧美主播福利视频| 少妇高潮久久久久久潘金莲| 日韩av在线网站| 日韩中文字幕不卡视频| 亚洲精品色婷婷福利天堂| 欧美成人高清视频| 国产成人av网| 欧洲精品久久久| www国产亚洲精品久久网站| 不卡伊人av在线播放| 欧美老妇交乱视频| 国产男女猛烈无遮挡91| 亚洲天堂免费观看| 亚洲少妇中文在线| 色婷婷亚洲mv天堂mv在影片| 91精品国产综合久久久久久久久| 亚洲精品国精品久久99热一| 日韩免费观看av| 久久免费国产精品1|