您好,登錄后才能下訂單哦!
這篇文章主要介紹“laravel服務容器的IoC模式是什么”,在日常操作中,相信很多人在laravel服務容器的IoC模式是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”laravel服務容器的IoC模式是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
1、依賴
IoC模式主要是用來解決系統組件之間相互依賴關系的一種模式。那么什么是依賴呢?下面給出依賴的實例
<?php //設計公共接口 interface Go_To_School { public function go(); } //實現交通工具類 class Foot implements Go_To_School { public function go() { echo 'walt to school'; } } //設計學生類,實現去學校時要依賴的交通工具實例 class Student { private $trafficTool; public function __construct() { //產生依賴 $this->trafficTool = new Foot(); } public function go_to_school() { $this->trafficTool->go(); } } $student = new Student(); $student->go_to_school();
這里要實現的功能是學生去學校,當創建了一個學生實例的時候,同時也創建了一個交通工具的實例。可以看到學生和交通工具之間不可避免的產生了一個依賴。在程序中依賴可以理解為一個對象實現某個功能時需要其他對象相關功能的支持。
當然交通工具還有很多,接著完善代碼
<?php //設計公共接口 interface Go_To_School { public function go(); } //實現不同交通工具類 class Foot implements Go_To_School { public function go() { echo 'walt to school'; } } class Car implements Go_To_School { public function go() { echo 'drive to school'; } } class Bicycle implements Go_To_School { public function go() { echo 'ride to school;'; } } /* * 少量的依賴并不會有太過直觀的影響,我們隨著這個例子逐漸鋪開,讓大家慢慢意識到,當依賴達到一個量級時,是怎樣一番噩夢般的體驗 */ class more implements Go_To_School { public function go() { //................... } } /* * * * * * more and more * * * * * */ //設計學生類,實現去學校時要依賴的交通工具實例 class Student { private $trafficTool; public function __construct() { //產生依賴 $this->trafficTool = new Foot(); //$this->trafficTool = new Car(); //$this->trafficTool = new Bicycle(); /* * * * * * more and more * * * * */ } public function go_to_school() { $this->trafficTool->go(); } } $student = new Student(); $student->go_to_school();
是不是很恐怖!當用new關鍵字在一個組件內部實例化一個對象時就解決了一個依賴,但同時也引入了另一個嚴重的問題——耦合。在簡單情況下可能看不出耦合有多大問題,但是如果需求改變,如需要實例化的交通工具是自行車、汽車甚至是在設計中還不太清楚的工具時,就需要改變實例化的對象,如果又有很多地方用到了這段代碼,而這個程序又不是你寫的,這時你面對的將是噩夢。所以,這里我們不應該在學生內部固化’交通工具‘的初始化行為,而轉由外部負責
2、簡單工廠模式
原理:由一個工廠類根據傳入的參數(一般是字符串參數),動態決定應該創建哪一個產品子類(這 些產品子類繼承自同一個父類或接口)的實例,并以父類形式返回。
適用情況:所有的產品子類都有同一個父類(或接口),屬于同一個產品系列 產品子類比較少的、創建操作比較簡單 。
在前面的實例中我們知道,交通工具的實例化過程是經常需要改變的,所以我們將這部分提取到外部來管理,這也就體現了面向對象設計的一個原則,及找出程序中會變化的方面然后將其和固定不變的方面相分離。一種簡單的實現方案是利用工廠模式,這里我們用簡單工廠模式實現。實例如下:
class TrafficToolFactory { public function createTrafficTool($name) { switch ($name){ case 'Foot': return new Foot(); break; case 'Car': return new Car(); break; case 'Bicycle': return new Bicycle(); break; default: exit('set trafficTool error!'); break; } } } class Student { private $trafficTool; public function __construct($trafficTool) { //通過工廠產生依賴的交通工具實例 $factory = new TrafficToolFactory(); $this->trafficTool = $factory->createTrafficTool($trafficTool); } public function go_to_school(){ $this->trafficTool->go(); } } $student = new Student('Car'); //$student2 = new Student('Foot'); //$student3 = new Student('Bicycle'); $student->go_to_school();
這里我們添加了“交通工具”工廠,在學生實例化的過程中指定需要的交通工具,則工廠生產相應的交通工具實例。在一些簡單的情況下,簡單工廠模式可以解決這個問題。我們看到學生和交通工具之間的依賴關系沒有了,但是卻變成學生和交通工具工廠之間的依賴。當需求增加時,我們需要修改簡單工廠,如果依賴增多,工廠將十分龐大,依然不利于維護。下一步就是我們今天的主要配角 —— DI
3、DI(Dependency Injection 依賴注入)
本文中提到的一系列依賴,只要不是由內部產生(比如初始化、構造函數 __construct 中通過工廠方法、自行手動 new 的),而是由外部以參數或其他形式注入的,都屬于依賴注入(DependencyInjection簡稱DI) 。實例如下:
class Student { private $trafficTool; public function __construct(Go_To_School $trafficTool) { $this->trafficTool = $trafficTool; } public function go_to_school(){ $this->trafficTool->go(); } } $car = new Car(); $student = new Student($car); $student->go_to_school();
現在初始化學生類時提供的參數必須是Go_To_School接口類的一個實例,即通過依賴注入的方式解決依賴問題,否則就會提示出錯。這里要注意,依賴注入要以接口的形式進行限制,不能隨意開放
4、IoC容器(Inversion of Control 控制反轉)
IoC是將設計好的類交給系統去控制,而不是在類內部控制。這稱為控制反轉。上例中我們是通過手動注入依賴,而IoC容器實現了依賴的自動注入。下面給出一個簡化版的例子。里面涉及到反射機制,網上有很多關于反射機制的講解,讀者可以自行查找,這里就不細說了。
class Container { //用于裝提供實例的回調函數,真正的容器還會裝實例等其他內容 //從而實現單例等高級功能 protected $bindings = []; //綁定接口和生成相應實例的回調函數 public function bind($abstract, $concrete=null, $shared=false) { //如果提供的參數不是回調函數,則產生默認的回調函數 if(!$concrete instanceof Closure) { $concrete = $this->getClosure($abstract, $concrete); } $this->bindings[$abstract] = compact('concrete', 'shared'); } //默認生成實例的回調函數 protected function getClosure($abstract, $concrete) { return function($container) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? 'build' : 'make'; return $container->$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; } //獲取綁定的回調函數 protected function getConcrete($abstract) { if(!isset($this->bindings[$abstract])) { return $abstract; } return $this->bindings[$abstract]['concrete']; } //實例化對象 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); } //解決通過反射機制實例化對象時的依賴 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); } }
這就是簡化版的IoC容器類,使用bind()函數進行服務綁定,使用make()函數來進行解析,最后在容器內由build()函數創建并返回實例。下面是具體如何使用
//實例化IOC容器 $ioc = new Container(); //填充容器 $ioc->bind('Go_To_School', 'Car'); //第一個參數'Go_To_School'是接口,第二個參數'Car'是交通工具類 $ioc->bind('student', 'Student'); //第一個參數'student'可以理解為服務別名,用make()實例化的時候直接使用別名即可,第二個參數'Student'是學生類 //通過容器實現依賴注入,完成類的實例化 $student = $ioc->make('student'); $student->go_to_school();
填充容器的時候也可以直接綁定自定義的回調函數:
$ioc->bind('Go_To_School', function (){ return new Car(); });
現在,我們不僅解除了學生類與交通工具類的依賴關系,而且容器類沒有和他們產生任何依賴。我們通過注冊、綁定(bind)的方式向容器中添加一段可以被執行的回調(可以是匿名函數、非匿名函數、類的方法)作為創建一個類的實例的方法,只有在真正的創建(make)操作被調用執行時,才會觸發。這樣一種方式,使得我們更容易在創建一個實例的同時解決其依賴關系,并且更加靈活。當有新的需求,只需另外綁定一個回調即可。例如現在我們想步行去學校,只要再綁定$ioc->bind('Go_To_School', 'Foot');就可以了。用何種方式去學校,我們可以自由的選擇。
通過上述例子可以看到IOC容器最核心的功能,解決依賴注入的根本問題。在實現過程中,沒有用new關鍵字來實例化對象,不需要人來關注組件之間的依賴關系,只要在容器填充過程中理順接口和實現類之間的關系及實現類與依賴接口之間的關系就可以流水線式的完成實現類的實例化過程。
到此,關于“laravel服務容器的IoC模式是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。