摘要:而依賴倒置原則的思想是,上層不應該依賴下層,應依賴接口。上面通過構造函數注入對象的方式,就是最簡單的依賴注入當然注入不僅可以通過構造函數注入,也可以通過屬性注入,上面你可以通過一個來動態為這個屬性賦值。
依賴倒置和控制反轉是一種編程思想,而依賴注入就是通過服務容器實現這種面向接口或者是面向抽象編程的思想概念理解 依賴倒置原則
依賴倒置是一種軟件設計思想,在傳統軟件中,上層代碼依賴于下層代碼,當下層代碼有所改動時,上層代碼也要相應進行改動,因此維護成本較高。而依賴倒置原則的思想是,上層不應該依賴下層,應依賴接口。意為上層代碼定義接口,下層代碼實現該接口,從而使得下層依賴于上層接口,降低耦合度,提高系統彈性
控制反轉當調用者需要被調用者的協助時,在傳統的程序設計過程中,通常由調用者來創建被調用者的實例,但在這里,創建被調用者實例的工作不再由調用者來完成,而是將被調用者的創建移到調用者的外部,從而反轉被調用者的創建,消除了調用者對被調用者創建的控制,因此稱為控制反轉。
要實現控制反轉,通常的解決方案是將創建被調用者實例的工作交由 IoC 容器來完成,然后在調用者中注入被調用者(通過構造器/方法注入實現),這樣我們就實現了調用者與被調用者的解耦,該過程被稱為依賴注入。
依賴注入不是目的,它是一系列工具和手段,最終的目的是幫助我們開發出松散耦合(loose coupled)、可維護、可測試的代碼和程序。這條原則的做法是大家熟知的面向接口,或者說是面向抽象編程。
通俗的說,在調用一個對象的方法,首先要實例化對象之后。 而所謂的注入,就是一種工廠模式的升華。由一個更高級的工廠(容器),來完成對象實例化,實現調用者與被調用者的解耦解決什么問題 實現調用者與被調用者的解耦
[info] 所謂的上層代碼依賴于接口,就是業務邏輯的實現是跳過了具體對象的抽象行為。比如我們要對用戶發消息,可以通過郵件發送,也可以通過短信發送。上層代碼不用關注其用什么發送,只發送即可(適配器模式)
interface Mail { public function send(); } class Email implements Mail { public function send() { echo "發送郵件" . PHP_EOL; } } class SmsMail implements Mail { public function send() { echo "發送短信" . PHP_EOL; } } // 注冊容器 class Register { private $_mailObj; // 構造函數里面已經約束了必須是實現了Mail接口的類的實例 public function __construct(Mail $mailObj) { $this->_mailObj = $mailObj; } public function doRegister() { // 一定會有send方法 $this->_mailObj->send();//發送信息 } } $emailObj = new Email(); $smsObj = new SmsMail(); $reg = new Register($emailObj); $reg->doRegister();//使用email發送 $reg = new Register($smsObj); $reg->doRegister($smsObj);//使用短信發送
使用構造函數注入的方法,使得它只依賴于發送短信的接口,只要實現其接口中的"send"方法,不管你什么方式發送都可以。上面通過構造函數注入對象的方式,就是最簡單的依賴注入;當然"注入"不僅可以通過構造函數注入,也可以通過屬性注入,上面你可以通過一個"setter"來動態為"mailObj"這個屬性賦值。
通過php反射機制實現自動注入真實的dependency injection container會提供更多的特性,如
自動綁定(Autowiring)或 自動解析(Automatic Resolution)
注釋解析器(Annotations)
延遲注入(Lazy injection)
c = $c; } public function doSomething() { $this->c->doSomething(); echo __METHOD__ , "我是周伯通B|"; } } class A { private $b; public function __construct(B $b) { $this->b = $b; } public function doSomething() { $this->b->doSomething(); echo __METHOD__ , "我是周伯通A|";; } } class Container { private $s = []; public function __set($k , $c) { $this->s[$k] = $c; } public function __get($k) { return $this->build($this->s[$k]); } /** * 自動綁定(Autowiring)自動解析(Automatic Resolution) * @param string $className * @return object * @throws Exception */ public function build($className) { // 如果是匿名函數(Anonymous functions),也叫閉包函數(closures) if ($className instanceof Closure) { // 執行閉包函數,并將結果 return $className($this); } if(!class_exists($className)){ throw new Exception("{$className} class is not exists"); } /** @var ReflectionClass $reflector */ $reflector = new ReflectionClass($className); // 檢查類是否可實例化, 排除抽象類abstract和對象接口interface if (!$reflector->isInstantiable()) { throw new Exception("Can"t instantiate this."); } /** @var ReflectionMethod $constructor 獲取類的構造函數 */ $constructor = $reflector->getConstructor(); // 若無構造函數,直接實例化并返回, (注意! 此處退出遞歸1) if (is_null($constructor)) { return new $className; } // 取構造函數參數,通過 ReflectionParameter 數組返回參數列表 $parameters = $constructor->getParameters(); // 遞歸解析構造函數的參數 $dependencies = $this->getDependencies($parameters); // 創建一個類的新實例,給出的參數將傳遞到類的構造函數。 return $reflector->newInstanceArgs($dependencies); } /** * @param array $parameters * @return array * @throws Exception */ public function getDependencies($parameters) { $dependencies = []; /** @var ReflectionParameter $parameter */ foreach ($parameters as $parameter) { /** @var ReflectionClass $dependency */ $dependency = $parameter->getClass(); if (is_null($dependency)) { // 是變量,有默認值則設置默認值 (注意,此處退出遞歸2) $dependencies[] = $this->resolveNonClass($parameter); } else { // 是一個類,遞歸解析 $dependencies[] = $this->build($dependency->name); } } return $dependencies; } /** * @param ReflectionParameter $parameter * @return mixed * @throws Exception */ public function resolveNonClass($parameter) { // 有默認值則返回默認值 if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); } throw new Exception("I have no idea what to do here."); } } /*// example1 $container = new Container(); $container->b = "B"; $container->a = function ($container){ return new A($container->b); }; // 從容器中取得A $model = $container->a; // output: C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A| // 實現依賴自動注入 $model->doSomething();*/ // example2 $di = new Container(); $di->php7 = "A"; // 自動注入classA /** @var A $php7 */ $foo = $di->php7; $foo->doSomething(); //C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A|
參考:
https://www.cnblogs.com/pains...
https://www.cnblogs.com/phppe...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/31380.html
摘要:起就在中內置了服務器但只是提供開發測試使用,不推薦使用中生產環境中。因為這個服務器接受處理請求時順序執行的,不能并發處理。這個內置的服務器使用起來非常的方便,你只需要執行下面的命令啟動服務器然后就可以訪問了。 PHP 5.4起就在CLI SAPI中內置了web服務器,但只是提供開發測試使用,不推薦使用中生產環境中。因為這個服務器接受處理請求時順序執行的,不能并發處理。 這個內置的web...
摘要:通過生成器來生成關聯數組下面每一行是用分號分割的字段組合,第一個字段將被用作鍵名。正常來說,產生的是一個,它的成員變量與函數不存在別名引用關系。關鍵字在的版本,生成器允許從其他生成器,可迭代對象或數組通過關鍵字來生成對應的值輸出 一般你在迭代一組數據的時候,需要創建一個數據,假設數組很大,則會消耗很大性能,甚至造成內存不足。 //Fatal error: Allowed memory ...
摘要:它使得在生產環境中啟用斷言為零成本,并且提供當斷言失敗時拋出特定異常的能力。錯誤和異常改變了大多數錯誤的報告方式。不同于傳統的錯誤報告機制,現在大多數錯誤被作為異常拋出。 PHP7性能 7最大的亮點,應該就是性能提高了兩倍,某些測試環境下甚至提高到三到五倍,具體可以了解以下鏈接: PHP7 VS HHVM (WordPress) HHVM vs PHP 7 – The Competit...
摘要:簡介是才有的新功能,它是用來導出或提取出關于類方法屬性參數等的詳細信息,包括注釋。 簡介 PHP Reflection API是PHP5才有的新功能,它是用來導出或提取出關于類、方法、屬性、參數等的詳細信息,包括注釋。 class Reflection { } interface Reflector { } class ReflectionException extends Exce...
摘要:實例化對象里面的所在哪個類就返回哪個類。訪問的是當前類有點像因為其是繼承了的方法,而調用的。由此可見,他們的區別只有在繼承中才能體現出來,如果沒有任何繼承,那么這兩者是沒有區別的。但如果是在靜態方法內本類的話,最好還是用 以static::來調用,是在運行的那個時刻才執行綁定操作; 父類中有個方法是延遲綁定的,在子類::調用這個方法的時候它又回到調用的子類開始向上找; exampl...
閱讀 2882·2023-04-26 02:49
閱讀 3455·2021-11-25 09:43
閱讀 3430·2021-10-09 09:43
閱讀 3008·2021-09-28 09:44
閱讀 2457·2021-09-22 15:29
閱讀 4529·2021-09-14 18:02
閱讀 2789·2021-09-03 10:48
閱讀 3434·2019-08-30 12:47