Laravel 源码学习笔记 6:服务容器之 App 解析实例

关于服务容器这块,已经有一个我感觉很棒的文章说明了,深入剖析 Laravel 服务容器
,这篇笔记主要记录一些看代码的收获
我们都知道app(xxxinterface:class)是为了解析这个接口绑定的依赖,也就是这个接口绑定的实现类,那如果是直接一个类呢比如app(xxx:class)有一天我就疑惑了,因为这种没有绑定在容器中,他是如何解析的?我就去看了下源码
在容器类中有make方法

public function make($abstract, array $parameters = [])
    {
        return $this->resolve($abstract, $parameters);
    }
    protected function resolve($abstract, $parameters = [])
    {

        $abstract = $this->getAlias($abstract);

        $needsContextualBuild = ! empty($parameters) || ! is_null(
            $this->getContextualConcrete($abstract)
        );

        // If an instance of the type is currently being managed as a singleton we'll
        // just return an existing instance instead of instantiating new instances
        // so the developer can keep using the same objects instance every time.
        // 如果已经存在该服务的实例就直接返回
        if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
            return $this->instances[$abstract];
        }

        $this->with[] = $parameters;

        $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)) {
            $object = $this->build($concrete);
        } else {
            $object = $this->make($concrete);
        }

        // If we defined any extenders for this type, we'll need to spin through them
        // and apply them to the object being built. This allows for the extension
        // of services, such as changing configuration or decorating the object.
        foreach ($this->getExtenders($abstract) as $extender) {
            $object = $extender($object, $this);
        }

        // If the requested type is registered as a singleton we'll want to cache off
        // the instances in "memory" so we can return it later without creating an
        // entirely new instance of an object on each subsequent request for it.
        if ($this->isShared($abstract) && ! $needsContextualBuild) {
            $this->instances[$abstract] = $object;
        }

        $this->fireResolvingCallbacks($abstract, $object);

        // Before returning, we will also set the resolved flag to "true" and pop off
        // the parameter overrides for this build. After those two things are done
        // we will be ready to return back the fully constructed class instance.
        $this->resolved[$abstract] = true;

        array_pop($this->with);

        return $object;
    }

所有的app解析,都是用的这个方法解析出对象,那如果直接传个类,他是怎么办呢?看上面代码发现有个$concrete = $this->getConcrete($abstract);里面是

protected function getConcrete($abstract)
    {
        //区分有上下文实现类的,比如不同控制器使用不同存储方式,返回不同实现类
        if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
            return $concrete;
        }

        // If we don't have a registered resolver or concrete for the type, we'll just
        // assume each type is a concrete name and will attempt to resolve it as is
        // since the container should be able to resolve concretes automatically.
        // 如果直接用app(axxx::class)这种方法,自定义的,就是直接返回当前这个类了,因为没有在容器中绑定
        if (isset($this->bindings[$abstract])) {
            return $this->bindings[$abstract]['concrete'];
        }

        return $abstract;
    }

由这个getConcrete方法可以发现,它会去判断容器中有没有存在这个绑定,有的话就会返回它的实现类,没有的话,就会返回它自己。所以我们自定义的类也可以这样解析出对象来调用里面的方法

$xxxClassObject = app(xxx::class);
$xxxClassObject->xxxClassMethod('调用方法');

服务容器:其实就是管理类的依赖和执行依赖注入的东西,里面主要就是存放了接口和实现类的绑定,有的一个请求只需要一个实例那就用单例绑定,普通的就用普通绑定,我们使用依赖注入的时候,就是让容器去解析一个对象出来,如果app(接口)就会去找对应的绑定的实现类,如果app(类)就会返回对应类的实例,其实也就是实现了解耦的过程,少调了new这个东西,也就是控制反转了
容器解析对象就是利用反射

有什么不对或有疑问的地方请大佬们指正:)

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!