Laravel 服務容器與服務提供者理解

參考
https://laravelacademy.org/po...
https://laravelacademy.org/po...

服務容器

控制反轉(IOC)與依賴注入(DI)

講的都是1個概念.

Ioc: 主對象依賴的某些對象原來在對象內部產生.現在把這個動作放到外面,比如Ioc容器,,IoC容器控制了對象生命週期,需要對象時,直接找容器,容器實例負責查找及創建依賴對象(也可以直接綁定已有對象的實例).

DI 由容器動態的將某個依賴關係注入到組件之中。依賴注入的目的並非爲軟件系統帶來更多功能,而是爲了提升組件重用的頻率,併爲系統搭建一個靈活、可擴展的平臺, 這個平臺就是基於IOC容器.

注入的原理是反射,根據類名創建實例,或者是Clouse,即閉包函數創建實例.

所以容器需要知道它負責的對象如何創建,這就是bind(綁定創建實例的閉包函數)和instance(綁定已有實例)的作用.

如何保存綁定大量對象?,就用array數組搞定:

#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,則調用產生,否則根據類名反射產生該實例

反射裏應該是一顆遞歸樹,因爲class A的constructor參數裏, 可能依賴B,B依賴C,D...

    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;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章