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

TP6依赖注入是如何实现的

5ed50b14c43a8511d8a9383e82ae375d.png

先看下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开发,学习研究欢迎使用,关注我们保持联系!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/562373.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信捷触摸屏c语言脚本_信捷触摸屏TG系列产品型号说明及功能介绍

产品介绍全新外观设计,比普通款更薄1677万色,画质细腻无痕,显示效果媲美液晶显示器下载、启动、运行,三位一体的超高速响应支持C语言脚本功能,运算、自由协议编写、绘图,提高编程自由度支持BMP、JPEG格式图…

基于java SSM springboot+redis网上水果超市商城设计和实现以及文档

作者主页:Java李杨勇 简介:Java领域优质创作者、【Java李杨勇】公号作者 简历模板、学习资料、面试题库、技术互助【关注我,都给你】 文末获取源码 主要技术实现:spring、 springmvc、 redis、 springboot、 mybatis 、sessio…

基于java SSM springboot景区行李寄存管理系统设计和实现

🍅 作者主页:Java李杨勇 🍅 简介:Java领域优质创作者🏆、Java李杨勇公号作者✌ 简历模板、学习资料、面试题库、技术互助【关注我,都给你】 🍅 欢迎点赞 👍 收藏 ⭐留言 &#x1f…

Spring、SpringMVC和SpringBoot之间的关系

1、Spring Spring是一个开源容器框架,它接管了Web层、业务层、DAO层、持久性层的组件,并可以配置各种bean并维护bean到bean的关系。 其核心是控制反转(IOC)和面向方面(AOP),这只是一个分层的轻量级开源框架。 2、SpringMVC Spring MVC属于Spr…

mysql 5.7.13 mac_Mac 安装mysql 5.7.13版本 登录及改密码

小白用户,首次安装5.7.13,刚开始有些蒙,改密码就就是个坑,好在还是解决了,记录一下心路历程:安装的过程很简单,就直接到官方下mysql dmg,一路下一步就可以装完..Ps:安装完毕之前会有…

java springboot经典面试题分享

1. SpringBoot 简介 SpringBoot 是简化 Spring 应用开发的一个框架。他整合了 Spring 的技术栈,提供各种标准化的默认配置。使得我们可以快速开发 Spring 项目,免掉 xml 配置的麻烦。降低 Spring 项目的成本。 2. SpringBoot 的优缺点 使编码配置部署都变…

基于java SSM springboot动物检疫信息管理系统设计和实现

作者主页:Java李杨勇 简介:Java领域优质创作者、【Java李杨勇】公号作者 简历模板、学习资料、面试题库、技术互助【关注我,都给你】 文末获取源码 主要技术实现:spring、 springmvc、 springboot、 springboot security权限控…

mysql for update场景_一个mysql死锁场景实例分析

前言最近遇到一个mysql在RR级别下的死锁问题,感觉有点意思,研究了一下,做个记录。涉及知识点:共享锁、排他锁、意向锁、间隙锁、插入意向锁、锁等待队列场景隔离级别:Repeatable-Read表结构如下create table t (id int…

基于java ssm springboot女士电商平台系统源码+文档设计

作者主页:Java李杨勇 简介:Java领域优质创作者、【Java李杨勇】公号作者 简历模板、学习资料、面试题库、技术互助【关注我,都给你】 文末获取源码 主要技术:spring, springmvc, springboot,mybatis, jquery , md5 ,bootstarp.…

基于java ssm springboot网上蛋糕商城项目设计和实现

🍅 作者主页:Java李杨勇 🍅 文末获取源码联系方式📝 主要技术:spring、 springmvc、 springboot、 mybatis 、 jquery 、 md5 、bootstarp.js tomcat、富文本编译器、拦截器等 主要功能:登录、注册、商品浏览、…

基于Java springboot+vue+redis前后端分离家具商城平台系统设计和实现

主要技术实现:spring、 springmvc、 springboot、 mybatis 、 jquery 、 md5 、bootstarp.js tomcat、富文本编译器、拦截器等 主要设计功能:用户登录、注册、商城分类、商品浏览、查看、购物车、订单、支付、以及后台的管理 4.3用户需求分析 用户…

jq 修改swal的标题_js-jquery-SweetAlert2【一】使用

一、下载安装地址:https://github.com/limonte/sweetalert2二、页面引用当然还有jquery三、示例3.1、基础结构window.οnlοadfunction(){swal("Here‘s a message!");//以下代码主要修改这里}3.2、精简用法1、标题【alert】-swal(string)swal("Here…

基于Java springmvc+mybatis酒店信息管理系统设计和实现

🍅 作者主页:Java李杨勇 🍅 简介:Java领域优质创作者🏆、【java李杨勇】公号作者✌ 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 临近学期结束&#xff…

基于JAVA SSM springboot实现的抗疫物质信息管理系统设计和实现

🍅 作者主页:Java李杨勇 🍅 简介:Java领域优质创作者🏆、【java李杨勇】公号作者✌ 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 临近学期结束&#xff…

基于java springmvc+mybatis学生考试系统设计和实现

🍅 作者主页:Java李杨勇 🍅 简介:Java领域优质创作者🏆、【java李杨勇】公号作者✌ 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 临近学期结束&#xff…

java文件编译为class文件需要键入什么命令_cmd命令行 编译Java 文件

【问题引入】 很多时候,需要用到命令行来进行Java文件的编译。在用习惯了IDE 可能会不清楚如何在cmd命令行窗口进行编译,简单的都还好,带有包路径的可能会让很多人觉得有点小头疼。最近试了一下,发现了问题,就研究整理了一下记录吧。 【注1】环境准备, JDK,classpath 都…

基于JAVA springboot+mybatis智慧生活分享平台设计和实现

🍅 作者主页:Java李杨勇 🍅 简介:Java领域优质创作者🏆、Java李杨勇公号作者✌ 简历模板、学习资料、面试题库、技术互助【关注我,都给你】 🍅 欢迎点赞 👍 收藏 ⭐留言 &#x1f…

springboot自动装配的原理你能说出来吗?

SpringMvc和SpringBoot对比 首先我们回顾下原来搭建一个springmvc的hello-word的web项目(xml配置的)我们是不是要在pom中导入各种依赖,然后各个依赖有可能还会存在版本冲突需要各种排除。当你历尽千辛万苦的把依赖解决了,然后还需…

基于javaweb宠物领养平台管理系统设计和实现

🍅 作者主页:Java李杨勇 🍅 简介:Java领域优质创作者🏆、【java李杨勇】公号作者✌ 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 临近学期结束&#xff…

mysql 事务sqlserver_SQLServer数据库:事务与隔离级别实例讲解

本文主要向大家介绍了SQLServer数据库:事务与隔离级别实例讲解,通过具体的内容向大家展现,希望对大家学习SQLServer数据库有所帮助。上班途中,你在一处ATM机前停了下来。正当你在敲入密码的时候,你的一位家人也正在镇上…