參考
https://laravelacademy.org/po...
https://laravelacademy.org/po...php
講的都是1個概念.html
Ioc: 主對象依賴的某些對象原來在對象內部產生.如今把這個動做放到外面,好比Ioc容器,,IoC容器控制了對象生命週期,須要對象時,直接找容器,容器實例負責查找及建立依賴對象(也能夠直接綁定已有對象的實例).laravel
DI 由容器動態的將某個依賴關係注入到組件之中。依賴注入的目的並不是爲軟件系統帶來更多功能,而是爲了提高組件重用的頻率,併爲系統搭建一個靈活、可擴展的平臺, 這個平臺就是基於IOC容器.數組
注入的原理是反射
,根據類名建立實例,或者是Clouse
,即閉包函數建立實例.閉包
因此容器須要知道它負責的對象如何建立,這就是bind(綁定建立實例的閉包函數)和instance(綁定已有實例)的做用.app
如何保存綁定大量對象?,就用array數組搞定:ide
#bind綁定後的binding數組: [ 'A\1': 返回new的閉包函數 or 具體實現類 or 類名 'A\2': 返回new的閉包函數 or 具體實現類 or 類名 ] #若是是`singleton`方法,實例存在instances數組,供下次使用. [ 'A\1': A\1實例, 'A\2': A\2實例 ]
有了綁定關係,剩下的就是如何解析實例了,函數build
,make
,resolve
等.函數
//container.php $concrete = $this->getConcrete($abstract); // We're ready to instantiate an instance of the concrete type registered for // the binding. This will instantiate the types, as well as resolve any of // its "nested" dependencies recursively until all have gotten resolved. if ($this->isBuildable($concrete, $abstract)) { //build $object = $this->build($concrete); } else { $object = $this->make($concrete); }
最終的核心動做在build
裏, 若是concrete是closure,則調用產生,不然根據類名反射
產生該實例post
反射裏應該是一顆遞歸樹,由於class A的constructor參數裏, 可能依賴B,B依賴C,D...ui
public function build($concrete) { //... if ($concrete instanceof Closure) { return $concrete($this, $this->getLastParameterOverride()); } try { $reflector = new ReflectionClass($concrete); } catch (ReflectionException $e) { throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e); } //... }
bind的基本原理就這樣了,而singleton是單例模式,生成的單例存儲會先存儲到instance數組.
全部類都這樣手動bind,固然麻煩,因而就有service provider
.
先register Provider, 它會調用每一個Provider實例裏的register和boot,完成具體的實例bind.
public function register($provider, $force = false) { if (($registered = $this->getProvider($provider)) && ! $force) { return $registered; } // If the given "provider" is a string, we will resolve it, passing in the // application instance automatically for the developer. This is simply // a more convenient way of specifying your service provider classes. if (is_string($provider)) { $provider = $this->resolveProvider($provider); } $provider->register(); // If there are bindings / singletons set as properties on the provider we // will spin through them and register them with the application, which // serves as a convenience layer while registering a lot of bindings. if (property_exists($provider, 'bindings')) { foreach ($provider->bindings as $key => $value) { $this->bind($key, $value); } } if (property_exists($provider, 'singletons')) { foreach ($provider->singletons as $key => $value) { $this->singleton($key, $value); } } $this->markAsRegistered($provider); // If the application has already booted, we will call this boot method on // the provider class so it has an opportunity to do its boot logic and // will be ready for any usage by this developer's application logic. if ($this->isBooted()) { $this->bootProvider($provider); } return $provider; }