TP6依赖注入是如何实现的

先看下app/provider容器文件,此文件会在thinkAPP实例化的时候

直接从新绑定类到的容器上。复制原有容器中的类

可以先看下thinkAPP 构造方法中的处理逻辑

 /**  * 架构方法  * @access public  * @param string $rootPath 应用根目录  */ public function __construct(string $rootPath = '') {     //设置thinkphp扩展的目录     $this->thinkPath = dirname(__DIR__) . DIRECTORY_SEPARATOR;     //项目更目录     $this->rootPath = $rootPath ? rtrim($rootPath, DIRECTORY_SEPARATOR     //应用根目录     $this->appPath = $this->rootPath . 'app' . DIRECTORY_SEPARATOR;     //runtime根目录     $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATO     //检测app/provider.php文件进行替换容器绑定     if (is_file($this->appPath . 'provider.php')) {         $this->bind(include $this->appPath . 'provider.php');     }     //将当前容器实例保存到成员变量「$instance」中,也就是容器自己保存自己的一个     static::setInstance($this);      保存绑定的实例到「$instances」数组中,见对应分析     $this->instance('app', $this);     $this->instance('thinkContainer', $this); }

在控制中可以使用app()->db 可以看到thinkApp中根本没有此属性,php的类中,调用一个类的不存在的属性就会自动进入魔术方法__get(),再来看看app类当中的__get方法,app类中没有找到集成的类中也就是thinkContainer 中直接搜索__get方法,就能找到。

 thinkContainer //$name就是就是没有定义的属性的名称 public function __get($name) {     return $this->get($name); }

找到当前类的get方法,首先是检查了以下容器中有没有,没有就直接实例化,进行调用make方法进行创建类的实例化。

 /**   * 获取容器中的对象实例   * @access public   * @param string $abstract 类名或者标识   * @return object   */ public function get($abstract) {     if ($this->has($abstract)) {         return $this->make($abstract);     }     throw new ClassNotFoundException('class not exists: ' . $abstract, $a }

make主要检测有没实例化过由实例化过后就直接返回使用就行,没有就需要利用类的反射来创建类的实例化,可以看到调用了本类的invokeClass方法

 public function make(string $abstract, array $vars = [], bool $newInstance = {          //如果已经存在实例,且不强制创建新的实例,直接返回已存在的实例     if (isset($this->instances[$abstract]) && !$newInstance) {         return $this->instances[$abstract];     }          //如果有绑定,比如 'http'=> 'thinkHttp',则 $concrete = 'thinkHttp'     if (isset($this->bind[$abstract])) {         $concrete = $this->bind[$abstract];         if ($concrete instanceof Closure) {             $object = $this->invokeFunction($concrete, $vars);         } else {             //重走一遍make函数,比如上面http的例子,则会调到后面「invokeClass             return $this->make($concrete, $vars, $newInstance);         }     } else {         //实例化需要的类,比如'thinkHttp'         $object = $this->invokeClass($abstract, $vars);     }     if (!$newInstance) {         $this->instances[$abstract] = $object;     }     return $object; }

invokeClass方法主要为了绑定参数然后进行实例化类,绑定参数由bindParams方法实现,而bindParams方法中的getObjectParam方法中又会回调make方法。

 /**   * 调用反射执行类的实例化 支持依赖注入   * @access public   * @param string $class 类名   * @param array $vars 参数   * @return mixed   */ public function invokeClass(string $class, array $vars = []) {     try {         //通过反射实例化类         $reflect = new ReflectionClass($class);         //检查是否有「__make」方法         if ($reflect->hasMethod('__make')) {             $method = new ReflectionMethod($class, '__make');             //检查是否是公有方法且是静态方法             if ($method->isPublic() && $method->isStatic()) {                 //绑定参数                 $args = $this->bindParams($method, $vars);                 //调用该方法(__make),因为是静态的,所以第一个参数是null                 //因此,可得知,一个类中,如果有__make方法,在类实例化之前会首                 return $method->invokeArgs(null, $args);             }         }         //获取类的构造函数         $constructor = $reflect->getConstructor();         //有构造函数则绑定其参数         $args = $constructor ? $this->bindParams($constructor, $vars) : [         //根据传入的参数,通过反射,实例化类         $object = $reflect->newInstanceArgs($args);         // 执行容器回调         $this->invokeAfter($class, $object);         return $object;     } catch (ReflectionException $e) {         throw new ClassNotFoundException('class not exists: ' . $class, $     } }

getObjectParam方法中是拿到当前类实例化的参数,找到当前参数是否是类,如果是就会直接再次调用make方法,如果下个参数还是个类的实例化结果,会再次进行回调,这就是一个类中可以无限制的注入多个类的原理,所以在使用的当中运用app()->make()来进行获取类的例化,更加方便简洁

 /**   * 获取对象类型的参数值   * @access protected   * @param string $className 类名   * @param array $vars 参数   * @return mixed   */ protected function getObjectParam(string $className, array &$vars) {     $array = $vars;     $value = array_shift($array);     if ($value instanceof $className) {         $result = $value;         array_shift($vars);     } else {         $result = $this->make($className);     }     return $result; }

总的来说,整个过程大概是这样的:需要实例化 Db 类 ==> 提取构造函数发现其依赖App 类==> 开始实例化 App 类(如果发现还有依赖,则一直提取下去,直到依赖全部加载完)==>将实例化好的依赖(App 类的实例)传入 Db类来实例化 Db类。

感谢您的阅读,如果对您有帮助,欢迎关注"CRMEB"头条号。码云上有我们开源的商城项目,知识付费项目,均是基于PHP开发,学习研究欢迎使用,关注我们保持联系!

@value 注入静态属性_TP6依赖注入是如何实现的相关推荐

  1. java什么是依赖注入_什么是依赖注入?

    转自 https://blog.csdn.net/coding_1994/article/details/80634810,这位作者写的很清晰. Spring 能有效地组织J2EE应用各层的对象.不管 ...

  2. 依赖注入原理(为什么需要依赖注入)

    0. 前言 在软件工程领域,依赖注入(Dependency Injection)是用于实现控制反转(Inversion of Control)的最常见的方式之一.本文主要介绍依赖注入原理和常见的实现方 ...

  3. 静态代理和依赖注入方式获取网店管家查询仓库信息接口

    请求的URL地址http://localhost/tp5.1/public/index.php/index/wdgj/wdgjwarehouselistGet?page=1&pageSize= ...

  4. php 依赖注入框架,通过实现依赖注入和路由,构建一个自己的现代化PHP框架

    如何提高自己编写代码的能力呢?我们首先想到的是阅读学习优秀的开源项目,然后写一个自己的web框架或类库组件.作为web开发者,我们通常都是基于面向对象OOP来开发的,所以面向对象的设计能力或者说设计模 ...

  5. python依赖注入_如何做依赖注入python方式?

    这一切都取决于情况.例如,如果您使用依赖注入来进行测试,所以您可以轻松地嘲笑某些内容 – 您可以经常放弃注入:您可以嘲笑您将注入的模块或类: subprocess.Popen = some_mock_ ...

  6. 什么是依赖注入 php,什么是依赖注入?

    译文首发于 什么是依赖注入,转载请注明出处. 本文是依赖注入(Depeendency Injection)系列教程的第一篇文章,本系列教程主要讲解如何使用 PHP 实现一个轻量级服务容器,教程包括: ...

  7. python依赖注入_什么是依赖注入?

    这篇文章是关于一般依赖关系注入和在PHP中实现依赖注入容器系列的第一部分. 今天我不会谈论容器然而我想以一些具体的示例介绍依赖注入的概念希望说明尝试去解决问题和它给开发者带来的好处.如果你已经知道依赖 ...

  8. php对象依赖注入作用,php面向对象依赖注入理解及代码举例分析解释

    依赖注入是通过类的构造函数.方法.或者直接写入的方式,将所依赖的组件传递给类的方式.一般通过构造函数注入的是强依赖关系的组件,setter方式用来注入可选的依赖组件. 现在,大多数流行的PHP框架都采 ...

  9. 什么是依赖注入,vue的依赖注入如何实现的

    允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深(这也是使用$parent不好实现的地方),并在起上下游关系成立的时间里始终生效. 不用再关心dom层级,只要在祖先组件内部就可以一直使 ...

最新文章

  1. C++知识点4——vector与string简述
  2. python3爬虫系列教程-Python3爬虫视频学习教程
  3. linux平台性能监控系统,Linux系统性能监控
  4. 3DSlicer9:FAQ-3
  5. 实例演示oracle注入获取cmdshell的全过程
  6. 一文说透产品信息结构图的本质
  7. MFC开发IM-第二篇、MFC picture 控件的用法
  8. Unit04 - 继承的意义(下) 、 访问控制 、 static和final
  9. 用户、话题、评论一网打尽,分享一个最强微博爬虫
  10. 盐城计算机考试时间安排,2019盐城中考具体时间安排 什么时候考试
  11. 微型计算机原理聂伟荣,微型计算机原理与应用 聂伟荣 第十章 串行通信技术 课件.pdf...
  12. Mini-USB接口的引脚定义与USB与miniUSB接口区别
  13. c语言8bit转10bit,Win10系统如何才能将8bit(位深度)设定变成10bit呢?
  14. OPPO发布小布虚拟人,开放面向开发者的多元AI能力
  15. 金杉号:2022什么工作最赚钱,未来十年最吃香的4个稳定的工作
  16. 2021年中国彩电行业发展现状分析,零售量首度跌破4000万大关,行业迎来艰难时刻「图」
  17. TypeError: argument of type ‘NoneType‘ is not iterable
  18. 我可以用计算机做图吗,【我用Word和excel画图分别怎么制作】电脑excle怎样制作画图...
  19. Redis网站热搜关键词加载实践,建议收藏
  20. Oracle:根据身份证号码查询年龄最大的人

热门文章

  1. iphone如何信任软件_苹果企业开发者证书成漏洞 盗版商发布破解版iPhone应用
  2. iphone双卡_单卡 iPhone 变双卡,3分钟搞定安卓备用机短信——IFTTT妙用
  3. python列表存储字符串_Python 基础知识全篇-字符串列表
  4. 高德地图看各省分界线_深度解读|高德宣布高精地图“百元时代”背后的商业逻辑是什么...
  5. 阿里云 linux mysql数据库_Linux Mysql数据库安全配置
  6. JAVA之编译期和运行期区别
  7. Java利用stream(流)对map中的values进行过滤、排序操作
  8. Shiro之UsernamePasswordTokenRememberMeAuthenticationTokenAuthenticationToken
  9. 无符号右移负数_关于负数的右移与无符号右移运算小结
  10. .net bitmap rgb数据_Python商务与经济统计学-数据描述