<dd id="y7hvi"><strong id="y7hvi"></strong></dd>
<output id="y7hvi"><pre id="y7hvi"></pre></output>
    <label id="y7hvi"></label>
    <small id="y7hvi"><menu id="y7hvi"><del id="y7hvi"></del></menu></small><listing id="y7hvi"><menu id="y7hvi"><s id="y7hvi"></s></menu></listing>
    <label id="y7hvi"><button id="y7hvi"></button></label><small id="y7hvi"></small>

    <listing id="y7hvi"></listing>
      您的位置 >>> 星想互聯 >>> 編程技術 >>> PHP高級編程
      依賴注入(DI)和Ioc容器
      點擊數:427  發布時間2020-06-06 20:55:26

      Laravel這個框架,用起來方便,理解起來不簡單。

      為什么不簡單?因為包含了一大堆所謂“先進”的概念,其中依賴注入(DI)和Ioc容器是比較核心的內容之一。

      我百度了一下,講PHP DI和Ioc的內容很少,更別說詳解Laravel ioc的了。

      在這里,我綜合了幾篇寫得比較典型的文章,以一個產品經理的身份,從用戶體驗的角度嘗試讓初學者也能比較容易理解這個2個概念。


      DI和Ioc就是一種設計模式,這個概念已經存在10幾年了,請先對面向對象編程和設計模式(DesignPatterns)有初步的理解:

      預先了解一下這三種模式:1. 工廠模式 2. 單例模式 3. 注冊器模式

      也請了解一下 interface 的用法和作用;


      如果上述內容你都不是很熟悉,沒關系,很簡單的,請接著看:


      1. 首先來看 依賴注入(DI):

      故事是這樣的:

      我們知道寫一個類的時候,類本身是有個目的的,類里面有很多方法,每個方法搞定一些事情;


      class Hookup {

       

      public function getPhone(){

           //此處省略

      }


      public function inviteHer(){

           //此處省略

      }


      public function giveGifts(){

           //此處省略

      }

      public function kissHer(){

           //此處省略

      }

      }

      比方說

      這個類是什么意思?Hookup就是泡妞的意思,里面有4個步驟,第一步打電話,第二部邀請她共進晚餐,第三步送禮物,第四步打波兒,第五步.....我只能幫你到這里了...


      別看只有4步,其實每一步都不簡單,第一步打電話,你得先要到人家電話吧,第二步邀請吃飯,你得提前訂好飯店吧,第三步送禮物,你得先買禮物吧~第四步Kiss,你總得抓住一個合適的機會吧;


      當你在專心處理Hookup的時候,我太了解你了,你只關心結果,也就是抱得美人歸,問電話號碼,訂餐,買禮物,找機會這種小事,就交給其他“類”處理吧。


      如下:

       require 'BuyGifts.php';



      class Hookup {

       

      public function getPhone(){

           //此處省略

      }


      public function inviteHer(){

           //此處省略

      }


      public function giveGifts(){

      $gift = new BuyGifts();

      $gift->select();

      $gift->pay();

      }

      public function kissHer(){

           //此處省略

      }

      }


      $paoniu = new hookup();

      $paoniu->giveGifts();


      這里面送禮物這個環節(比較懶,其他的不寫了),就引入了BuyGifts這個類,買禮物這種小事,就交給BuyGifts這個秘書去處理吧。


      所以,一切問題的出發點,就是在一個類中調用其他類,我們要解決的,就是在這過程中會發生的問題。


      Hookup這個可以稱之為主類,BuyGifts稱之為次類,為了實現主類的目標,要依賴很多次類來配合。


      好,現在你已經知道什么是依賴了。


      問題來了,F在講正經的。


      比方說你很忙,你不僅要泡妞,還要開公司,做生意,沒事打打高爾夫球什么的。這每一件事都是一個“主類”,BuyGifts 這種“次類” ,除了泡妞,也可以放在 做生意這個類里面調用,做生意也要送禮的嘛,當然還可以應用在別的主類。 


      如果BuyGifts被調用很多次,哪一天需要把名字改了,那你就必須在眾多主類中逐一修改。

      還有就是,每一次調用都要new實例化一次。

      這樣做不科學,你也知道。


      怎么辦: 工廠模式

      工廠模式很簡單,就是來幫助你批量實例化“次類”的。也就是說,用了工廠模式,你的主類中將不會再出現new這樣的關鍵字。


      看實例,有3個類 哦:


      -----   Factory.php    ----------


      include 'BuyGifts.php'


      class Factory {


      static function getPhone(){

       

      return new getPhone;

      }



      static function BuyGifts(){

       

      return new BuyGifts;

      }


      //……下面還有很多,此處省略


      }


      -----   BuyGifts.php    ----------


      class  BuyGifts{

       

      public function select(){

      //此處省略 }


      public function pay(){

      //此處省略 }


      }


      -----   Hookup.php    ----------


      require 'BuyGifts.php';

      require 'Factory.php ';


      class Hookup {


      private $gift;

       

      public function getPhone(){

           //此處省略

      }


      public function inviteHer(){

           //此處省略

      }


      public function giveGifts(){

      $this->gift = Factory::BuyGifts();

      $gift->select();

      $gift->pay();

      }

      public function kissHer(){

           //此處省略

      }

      }


      $paoniu = new hookup();

      $paoniu->giveGifts();



      你看,現在主類Hookup 要調用次類BuyGifts,就得先去找Factory類,Factory就變成中介了。

      Factory這個中介的主要服務就是幫 你實例化次類,另外管理很多次類(工廠嘛),這樣你就不用直接與次類發生關系。


      這個過程就叫做 解耦,不管次類怎么變,你找工廠就可以了。


      可是這樣做問題依舊存在,,當我們在很多主類里調用了工廠及其方法,可是有一天發現工廠類要改名,,或者工廠里面的方法要改名呢?那我們還不是得逐一改主類?雖然這種情況不多,但是這種不講信譽的“黑中介”也是偶爾會出現的。


      怎么辦呢?我們對這個Factory 中介 也得 防 一手。


      -----   Hookup.php    ----------


      require 'BuyGifts.php';

      require 'Factory.php ';


      class Hookup {


      private $gift;

       

      public function getPhone(){

           //此處省略

      }


      public function inviteHer(){

           //此處省略

      }


      public function giveGifts(){

      $gift->select();

      $gift->pay();

      }


      public function kissHer(){

           //此處省略

      }


      public function setGift($instance){

      $this->gift = $instance;

      }

      }


      $paoniu = new hookup();

      $paoniu->setGift(Factory::BuyGifts()); // 看到 Factory已經滾粗 我們的主類了

      $paoniu->giveGifts();


      現在Hookup類就像一個公司,作為老板的你只關心怎么泡妞,臟活累活交給別人干,于是你設立了一個setGift采購部門,這個部門專門負責和Factory中介打交道,這樣Factory中介就完全滾粗你的視野了。


      Factory這個被依賴的對象 是通過參數 從外部 注入到 類內容的 靜態 屬性 實現實例化的,這個就是依賴注入。


      可以聰明的你馬上發現,我擦,setGift 你這個部門就負責采購gift?我要打電話,發預約邀請難道還要setPhone,setInvitation嗎?


      這樣主類里面要寫很多set方法,外面要調用很多次set方法,你會發現,更不科學了。

      里面:

      public function setGift($instance){

      $this->gift = $instance;

      }

      public function setPhone($instance){

      $this->phone = $instance;

      }


      public function setInvitation($instance){

      $this->Invitation = $instance;

      }


      ….


      外面:


      $paoniu->setGift(Factory::BuyGifts());

      $paoniu->setPhone(Factory::GetPhone());

      $paoniu->setInvitation(Factory::SendInvitation());


      ….



      這個時候,你已經把Factory 趕出 Hookup公司了,所以,公司內部的事情,只能你自己搞定了。

      公司外部的業務,這時Factory中介 又屁顛屁顛的跑過來找你,提出一個方案:


      我們來搞個“總代”怎么樣?


      class TopFactory {


      public static function all_Agents_in_one(){

       

      $paoniu_agent = new hookup();

                $paoniu_agent->setGift(Factory::BuyGifts()); 

      $paoniu_agent->setPhone(Factory::GetPhone());

               $paoniu_agent->setInvitation(Factory::SendInvitation());

       

      return $paoniu_agent;

      }


      }


      黑中介Factory對你說:“你看我搞了個總代公司(TopFactory),你在外面也不要new啊,set什么的了,我全包了。


      于是現在你在外面要做的變簡單了:


      $paoniu = TopFactory::all_Agents_in_one();

      $paoniu->giveGifts();//giveGifts里面就可以調用Buygifts了;

      $paoniu->getPhone();

      ….



      到現在為止,你已經有一套完整的 依賴注入方案了,這個方案組建的時候雖然有點復雜(層層轉包),但是一旦建好,維護起來比較方便。


      可是,別忘了公司內部的事情還沒解決哪,另外要提醒你,你是程序員,不是老板,所以Factory那一部分也是你的活~~~



      需要一種更高級的方案,讓程序員的生活變得Easier一些。

      這個方案就是IoC容器,IoC容器首先是一種類注冊器,其次它是一種更高級的依賴注入方式。


      它和工廠Factory其實性質一樣,都是中介代理,但實現機制不一樣。



      工廠Factory 把 次類 一一對應 注冊到 類中的 實例化靜態方法中;

      IoC容器是把 次類 實例化對象 依次 注冊到 類中一個靜態數組;



      IoC容器的設計模式叫做 注冊器模式;


      看實例:

      ———Di.php——-

      class Di {

       

      protected static $objects;


      static function set($key, $object){


      self::$objects[$key]=$object;


      }


      static function get ($key){


      return self::$objects[$key];


      }


      static function unset ($key){


      unset(self::$objects[$key]);


      }



      }



      -----   Hookup.php    ----------


      require ‘BuyGifts.php';

      require 'Factory.php ';

      require 'Di.php ';


      class Hookup {


      private $di;


      function __construct(Di &$di){

             $this->_di = $di;

          }

       

      public function getPhone(){

           //此處省略

      }


      public function inviteHer(){

           //此處省略

      }


      public function giveGifts(){

      $this->di->get(‘BuyGifts’)->select();

      $this->di->get(‘BuyGifts’)->pay();

      }


      public function kissHer(){

           //此處省略

      }


      public function setGift($instance){

      $this->gift = $instance;

      }

      }


      $di = new Di();

      $di->set(‘BuyGift’, function(){

      return Factory::BuyGift();

      }



      $paoniu=new Hookup($di);

      $paoniu->giveGifts();



      ———-


      可以看到,IoC模式才是真正的總代,它連公司內部的事情也管了。和設立set部門相比,set只能處理一個個單獨的業務,比如setGift,setPhone,setInvitation,之類的,,而ioc容器把這些實例全部放在一個數組里統一處理,并且還可以重新命名(鍵名),實現了完全的解耦。




      請注意的是,我們在注冊Ioc容器的時候,是這樣寫的:

      $di->set(‘BuyGift’, function(){

      return Factory::BuyGift();

      }


      而沒有這樣寫:

      $di->set(‘BuyGift’, Factory::BuyGift());



      第一個參數是數組的鍵名,第二個參數是數組的值;


      第一種寫法用了回調函數,它只有在讀取數組的值的時候才會被執行;

      第二種方法直接實例化成一個對象,保存到數組的值中。第二種方法會比較占資源。

      另外我們發現

      $di = new Di();

      $di->set(‘BuyGift’, function(){

      return Factory::BuyGift();

      }



      $paoniu=new Hookup($di);

      $paoniu->giveGifts();



      這里面怎么還有new呢,我們用靜態方法和Factory寫得優雅一些:

      Di::set(‘BuyGift’, function(){

      return Factory::BuyGift();

      } //注冊到容器

      $paoniu=factory::Hookup(factory::DI()); // 將容器注入主類

      $paoniu->giveGifts(); //這里就可以調用BuyGift()這個次類(依賴類);




      好了,我們來看看Laravel Ioc容器 是怎么用的:


      綁定類到容器


      App::bind('foo', function()

      {

          return newFooBar;

      });


      App 就是Ioc容器,bind就是set方法,’foo’ 就是數組中 實例的 鍵名;



      至此,我們已經對Ioc容器有了一個比較清楚的認識,我們已經了解了工廠模式,注冊模式,依賴注入等知識,其實依賴注入有3種方式,,一種就是set注入(單類注入),一種是容器注入(Ioc),還有一種是接口注入(Interface);前兩種我們已經學習過了,后一種放在本文的第二部分來講。


      在本文的第二部分,我們將詳細講解LaravelIoC的用法,為什么說Laravel理解起來比較難,因為它的設計不是入門級別的,而是專業級別的,比前面講的要復雜許多,但是看官方文檔,寥寥數語,真有種想砸電腦的沖動。

      來源:咸寧網站建設
      新天线宝宝