laravel5.5 简单聊聊dependency inject

场景

laravel5.5 service container中关于依赖注入的描述

Alternatively, and importantly, you may “type-hint” the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, queue jobs, middleware, and more. In practice, this is how most of your objects should be resolved by the container.
在controller ,queue jobs, middleware,以及其他的一些地方在__construct 方法中引入 type-hint dependency 会自动触发service container的resove方法

那下面就来追踪下实现的整个流程

素材准备

  • 定义一个简单的类InjectController , __construct 引入App\Http\Repository\LessonRepository::class
<?php

namespace App\Http\Controllers;

use App\Http\Repository\LessonRepository;

class InjectController extends Controller
{
   private $repository;

   /**
    * InjectController constructor.
    * @param $repository
    */
   public function __construct(LessonRepository $repository)
   {
       $this->repository = $repository;
   }

   public function sayHello()
   {
       try {
           $this->repository->sayHello();
       } catch (\Exception $e) {
           $msg = $e->getMessage();
           $status = 1478;
           return response()->json(compact('status', 'msg'));
       }
   }
}

  • 定义App\Http\Repository\LessonRepository::class
<?php

namespace App\Http\Repository;

use App\Lesson;
use App\TransForm\LessonTransForm;

class LessonRepository
{

    public function sayHello()
    {
        dump("laravel's injection is working!");
    }
}
  • 定义路由 Route::get(’/inject’, ‘InjectController@sayHello’);

源码分析

  • 简单访问
  • 简单访问
  • 是否触发了service container 的make方法
    • 修改Illuminate\Foundation\Application make function 添加一行
      • 修改make方法
      • 访问路由
        • make 修改后的结果
      • 这说明的确触发了service container resove function , 而且此时$abstract === "App\Http\Repository\LessonRepository"
  • 下面就进入了service container resolve 的实现过程, 具体的实现可以参考之前的一篇博文laravel 简单聊聊singleton的实现过程
    • resolve function 具体代码见源码
    • $concrete = $this->getConcrete($abstract); 得到$concrete=“App\Http\Repository\LessonRepository”
    • if ($this->isBuildable($concrete, $abstract)) { $object = $this->build($concrete);} build 实例
      • if (is_null($constructor)) {array_pop($this->buildStack);return new $concrete;} 利用reflection class 简单的测试后,就返回了App\Http\Repository\LessonRepository实例
    • 所以在InjectController __construct中注入的是App\Http\Repository\LessonRepository::class实例

源码


//  Illuminate\Container\Container 

    /**
     * Resolve the given type from the container.
     *
     * @param  string  $abstract
     * @param  array  $parameters
     * @return mixed
     */
    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;
    }

    /**
     * Determine if the given concrete is buildable.
     *
     * @param  mixed   $concrete
     * @param  string  $abstract
     * @return bool
     */
    protected function isBuildable($concrete, $abstract)
    {
        return $concrete === $abstract || $concrete instanceof Closure;
    }

    /**
     * Instantiate a concrete instance of the given type.
     *
     * @param  string  $concrete
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    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);
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值