Laravel 之道第六章:服务容器之 make

栏目: PHP · 发布时间: 6年前

内容简介:Laravel 之道第六章:服务容器之 make

先来段代码

下面是 public/index.php 入口文件的一段代码,相信大家都见过

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

它作用解析出在服务容器 bindings 属性中以 'Illuminate\Contracts\Http\Kernel' 为键,对应的服务对象。据上一章我们知道是 'App\Http\Kernel' 的类对象

注意:以 'Illuminate\Contracts\Http\Kernel' 为键,实际对应不是 'App\Http\Kernel' 的类对象,而是对应能够生成 'App\Http\Kernel' 类对象的闭包函数。

那么他是如何解析出的呢,我们看一下源码

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

实际调用了 resolve 方法,我们看一下 resolve 方法。

看下面这方法,是不是头大,这么多,其实核心的就那么几个地方,我已标注

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;

    // ★核心二★:通过 $abstract 到 bindings 属性中取得生成对象的闭包函数,没有则返回 $abstract 本身
    $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.
    // ★核心三★:判断是否可以创建对象,来确定调用 build 方法还是重新调用 make 方法
    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;
}

由于第一次执行,核心一忽略。当以 'Illuminate\Contracts\Http\Kernel' 为 $abstract 时,获取的闭包函数定义的位置如下

protected function getClosure($abstract, $concrete)
{
    return function ($container, $parameters = []) use ($abstract, $concrete) {
        if ($abstract == $concrete) {
            return $container->build($concrete);
        }

        return $container->make($concrete, $parameters);
    };
}

会执行上面代码 function 里面的内容,因为 Illuminate\Contracts\Http\Kernel 不等于 App\Http\Kernel ,故以 App\Http\Kernel 为 $abstract 重新调用了 make 方法

此时的 make 方法可以执行到 build 方法,我们来看一下

public function build($concrete)
{
    // If the concrete type is actually a Closure, we will just execute it and
    // hand back the results of the functions, which allows functions to be
    // used as resolvers for more fine-tuned resolution of these objects.
    if ($concrete instanceof Closure) {
        return $concrete($this, $this->getLastParameterOverride());
    }

    $reflector = new ReflectionClass($concrete);

    // If the type is not instantiable, the developer is attempting to resolve
    // an abstract type such as an Interface of Abstract Class and there is
    // no binding registered for the abstractions so we need to bail out.
    if (! $reflector->isInstantiable()) {
        return $this->notInstantiable($concrete);
    }

    $this->buildStack[] = $concrete;

    $constructor = $reflector->getConstructor();

    // If there are no constructors, that means there are no dependencies then
    // we can just resolve the instances of the objects right away, without
    // resolving any other types or dependencies out of these containers.
    if (is_null($constructor)) {
        array_pop($this->buildStack);

        return new $concrete;
    }

    $dependencies = $constructor->getParameters();

    // Once we have all the constructor's parameters we can create each of the
    // dependency instances and then use the reflection instances to make a
    // new instance of this class, injecting the created dependencies in.
    $instances = $this->resolveDependencies(
        $dependencies
    );

    array_pop($this->buildStack);

    return $reflector->newInstanceArgs($instances);
}

此时的 $concrete 等于 'App\Http\Kernel',会调用 PHP 内置的反射类,对 App\Http\Kernel 进行处理。

关于 ReflectionClass

官方文档

ReflectionClass:我的理解是,这是一个对类进行处理的对象,它甚至能够获取类中的注释,执行类中的私有方法;getConstructor 返回一个 ReflectionMethod 对象,它可以对类中方法进行更进一步处理和控制,比如获取方法调用时的参数列表,包含参数的类型约束,这点很重要,因为它是 Laravel 实现依赖注入的手段;反射方法对象中的 getParameters 将返回一个 ReflectionParameter 对象,它里面就包含了类型约束和参数名称。

$instances = $this->resolveDependencies(
    $dependencies
);

看到上面这段代码了吗,resolveDependencies 方法,就是解析出类构造方法中的约束类,通过多次 make 自动获取所依赖的对象,然后通过反射类的 newInstanceArgs 实例化

最终获取了 App\Http\Kernel 类的对象,并且仅仅通过一行字符串,其中构造函数所依赖的对象,全部由 make 自动处理,用户可以不再管理那个依赖这个依赖了,不仅变得方便、变得解耦,还变得功能健全

本文章首发在 Laravel China 社区

我们是一群被时空压迫的孩子。 ---- 爱因斯坦

以上所述就是小编给大家介绍的《Laravel 之道第六章:服务容器之 make》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Google 广告高阶优化(第3版)

Google 广告高阶优化(第3版)

【美】Brad Geddes(布兰德.盖兹) / 宫鑫、康宁、王娜 / 电子工业出版社 / 2015-9 / 99.00元

《Google 广告高阶优化(第3版)》可以说是Google AdWords的终极指南,内容非常丰富,第三版在内容上进行了全面更新。介绍了AdWords的最新最完整的功能,阐释其工作原理,也提供了相应的优化方法、策略和实践教程,读者可以随时在自己的PPC广告系列中进行实践。第三版增添了50多页新内容,涵盖Google系统最近的所有变动,包括广告系列结构的变化、出价调整器、重定向、视频广告功能、全新......一起来看看 《Google 广告高阶优化(第3版)》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试