<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                在開始之前要明確一個概念,不管是設計模式,還是依賴注入等等,都是為了實現模塊化.所謂模塊化就是希望一個軟件是由很多子模塊組成的,這些模塊之間的依賴程度盡量的低,也就是如果系統中不需要某一個功能,那么只要移除這個功能所對應的模塊就可以了. 那么,我們今天要說的服務容器就是為了實現上面的功能.你應該聽過,Laravel中的服務容器其本質上是一個IoC容器,但是好像隊IoC又不是很了解,講來講去優點很多,功能很強勁.但是不懂原理怎么用都不踏實啊.所以,這里我們自己來實現一個IoC容器,洞察其本質. > 在開始之前,先說明一點,閱讀本篇文章至少要保證有一下的基礎知識: > > * php反射用法 > > * 閉包的use用法 > > 如果不懂上面的內容,請先補充.避免閱讀代碼時候產生的不適感. Container.php ~~~ <?php class Container { //用于提供實例的回調函數,真正的容器還會裝實例等其他內容.從而實現單列等高級功能 public $binding = []; //綁定接口和生成相應實例的回調函數 public function bind($abstract, $concrete = null, $shared = false) { if (!$concrete instanceof Closure) { //如果提供的參數不是回調函數則產生默認的回調函數 $concrete = $this->getClosure($abstract, $concrete); } $this->binding[$abstract] = compact('concrete', 'shared'); } //默認生成的實例的回調函數 protected function getClosure($abstract, $concrete) { //生成實例的回調函數,$c一般為IOC容器對象,在調用回調生成實例時提供 //即build函數中的$concrete($this) return function ($c) use ($abstract, $concrete) { $method = ($abstract == $concrete) ? 'build' : 'make'; //調用的是容器的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; } public function isBuildable($concrete, $abstract) { return $concrete === $abstract || $concrete instanceof Closure; } //獲取綁定的回調函數 protected function getConcrete($abstract) { if (!isset($this->binding[$abstract])) { return $abstract; } return $this->binding[$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($paramters) { $dependencies = []; foreach ($paramters as $paramter) { //獲取到參數名稱. $dep = $paramter->getClass(); if(is_null($dep)){ $dependencies = null; }else{ $dependencies[] = $this->resolveClass($paramter); } } return (array)$dependencies; } /** * 實例化 構造函數中所需要的參數. */ protected function resolveClass(ReflectionParameter $parameter) { $name = $parameter->getClass()->name; return $this->make($name); } } ~~~ 這就是一個IoC容器的實現代碼.乍一看,很麻煩.其實真的蠻麻煩的 =_=,如果是第一次接觸的話,并不是那么好消化,這里再給出使用IoC容器的代碼 ~~~ <?php require __DIR__ . '/Container.php'; interface TrafficTool { public function go(); } class Train implements TrafficTool { public function go() { echo "train...."; } } class Leg implements TrafficTool { public function go() { echo "leg.."; } } class Traveller { /** * @var Leg|null|Train * 旅行工具 */ protected $_trafficTool; public function __construct(TrafficTool$trafficTool) { $this->_trafficTool = $trafficTool; } public function visitTibet() { $this->_trafficTool->go(); } } //實例化IoC容器 $app = new Container(); //綁定某一功能到IoC $app->bind('TrafficTool', 'Train'); $app->bind('travellerA', 'Traveller'); // 實例化對象 $tra = $app->make('travellerA'); $tra->visitTibet(); ~~~ 運行例子發現會輸出:train...這個例子假設旅行者去青藏旅行,可以坐火車(train)或者走路(leg)去青藏. 好了,其實這樣子本篇文章就可以結束了,因為所有的答案都在IoC容器的實現中, 但是為了可以更好的理解上面的代碼,我們繼續往下分析. 首先,希望你可以運行一下上面的代碼,雖然簡單的運行代碼并不會幫助你理解代碼,但是一個可以運行的例子會讓人比較踏實,能夠更有把握的理解代碼. 在深入每一行代碼之前,我們從整體上來分析,IoC解決了一個什么問題?簡單點說,就是我們再實例化對象的時候不用使用new了,有了IoC容器之后,我們調用make函數就可以實例化出一個對象了.然而,你發現,Traveller的構造函數是需要一個參數的,可是我們好像并沒有提供這個參數? 這就是IoC強大之處了, 調用make實例化對象的時候,容器會使用反射功能,去分析我們要實例化對象的構造函數,獲取構造函數所需的每個參數,然后分別去實例化這些參數,如果實例化這些參數也要參數,那么就再去實例化參數的參數.....=_=.到最后成功實例化我們所需要的traveller了.在Container的build函數就是使用反射來實例化對象. 但是,有一個問題了,IoC容器怎么知道實例化Traveller的時候需要的參數train,而不是leg? 其實,IoC容器什么都不知道,IoC會實例化哪些對象都是通過bind函數告訴IoC的,上面的例子兩次調用bind函數,就是告訴Ioc可以實例化的對象有Train和Traveller. 再通俗講就是:當需要當我們需要TrafficTool這個服務的時候去實例化Train這個類,需要一個travellerA的旅行者的時候去實例化Traveller類.而Train這個就是travellerA就是去青藏的方式. 這樣子如果想要走路去青藏的話只要把$app->bind('Visit', 'Train');改為$app->bind('Visit', 'Leg');就可以. 可是,這上面的這些有什么意義?直接$tra = new Traveller($trafficTool)來實例化對象好像也沒有什么不好的. >使用new來實例化對象的時候,會產生依賴.比如上面$tra = new Traveller($trafficTool),這說明我們要創建一個Traveller之前得有一個$trafficTool,即Traveller依賴于trafficTool.當使用new來實例化Traveller的時候,Traveller和trafficTool之間就產生了耦合.這樣,這兩個組件就沒辦法分開了. 而使用IoC是怎么解決這個問題的,之前說過,如果想要如果想要走路去青藏的話只要把$app->bind('Visit', 'Train');改為$app->bind('Visit', 'Leg');就可以.這樣子,使用何種方式去青藏,我們可以自由的選擇. 我們站在Laravel框架設計者的角度去想,設計者肯定希望一個框架提供的功能越多越好,但是又要保證強大的同時又不會限制使用者.最好可以保證使用者想實現什么奇怪的需求都可以.那么功能強大但是又不局限的最好方法就是什么都不做,提供一個強大的IoC容器.所有需要實現的功能都變成一個個服務,需要什么服務就把服務注冊(即調用bind函數)到IoC中,然后讓IoC去管理依賴. 開發者想到一個變態的需求:走路去青藏,那么只要你實現了走路去青藏這個功能,然后把這個功能當做一個服務注冊到IoC中,以后你需要這個服務的時候IoC就幫你實例化這個服務.當開發者回歸正常之后覺得還是坐火車去吧,于是不注冊走路這個功能,實現坐火車的功能,然后注冊這個功能.下次IoC實例化的時候就是實例化坐火車這個功能了. 好了,剩下的部分就是一行一行的閱讀Container的代碼了,Laravel框架中的服務容器代碼也是這個樣子,只是功能更加強悍.但是核心是一樣的,上面的代碼懂了以后再使用Laravel框架就會更加游刃有余了. 文章雖短.但是內容很多.尤其是代碼,雖然可能只是短短的一個例子,但是包含了很多內容.值得好好分析,這里放個彩蛋:Traveller中構造函數參數類似為TrafficTool,是一個接口.但是實例化的是Train.這里體現了設計模式的一個原則 > 面對接口編程,而不是面對實現編程.
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看