# 依赖注入 * * * * * 依赖注入其实本质上是指对类的依赖通过构造器完成自动注入。 说白了就是自动注入对象,数组,其他值 等。 说到依赖注入就不得不提到容器,现在主流开发框架都有容器的概念,一个杯子可以理解为一个容器,一个水桶也可以理解为容器,咱们不管容器的载体是谁,只需要知道在咱们代码中容器就是装数据滴。 依赖注入一般是提前通过文件定义,然后解析文件找到对应的类实例化对象给予到容器中。 还可以在生命周期过程中将对象或其他数据先放入容器中,在后续环节进行使用。 总之玩法五花八门,为了解决的问题就是咱们用对象不用new了,咱们用数据不用重新写逻辑了 等。 下面看看OneBase的依赖注入如何以TP5为容器。 ~~~ /** * 控制器层引用业务逻辑层 * 执行查询文章列表逻辑 * 前缀 logic */ $this->logicArticle->getArticleList(); /** * 业务逻辑层引用模型层 * 执行模型查询文章列表 * 前缀 model */ $this->modelArticle->getList(); /** * 业务逻辑层引用验证层 * 执行文章分类数据编辑场景验证 * 前缀 validate */ $this->validateArticleCategory->scene('edit')->check([]); /** * 业务逻辑层引用服务层 * 执行存储服务下的七牛驱动进行文件上传 * 前缀 service | driver */ $this->serviceStorage->driverQiniu->uploadFile(130); ~~~ 看过OneBase源码应该可以发现,咱们并没有看到对象 new 的过程,也没有看到引入相关文件,为什么就能执行进去呢?更神奇的是还能自动分辨代码是在admin模块还是common模块。。。 下面来讲解下实现原理 从系统架构中可以看出来,OneBase的控制器根源在于公共控制器ControllerBase,打开后找到__get这个方法,此处简单的介绍下这个方法就是当你获取对象属性值时没找到的时候就会执行这个方法。 代码如下 ~~~ /** * 获取逻辑层实例 */ public function __get($name) { !str_prefix($name, LAYER_LOGIC_NAME) && exception('逻辑层引用需前缀:' . LAYER_LOGIC_NAME); return model(sr($name, LAYER_LOGIC_NAME), LAYER_LOGIC_NAME); } ~~~ 既然在公共控制器而其他控制器都继承了公共控制器,那么就说明在其他控制器中调用属性找不到就会执行到这里来咯。 $this->logicArticle->getArticleList(); this 当然就是当前控制器对象啦,logicArticle 如果自己之前没有在控制器中定义那肯定是找不到咯,所以就执行过来了。 get 方法中进行了前缀的检测,如果不是 logic 开头则抛出异常提示,若前缀没问题则调用TP的model函数找到逻辑层下的逻辑对象返回。 打开model函数一路追踪下去会发现根源实际上在Loader类中,而此类中的对象是做了单例模式,意味着在一次生命周期中多次调用实际上是没有new新对象的。 现在就可以理解了为什么OneBase可以直接$this->logicArticle就执行进了业务逻辑层,是因为this对象中找不到,就进了get方法,然后通过TP加载的对象,这就是设计上的一个小技巧,以后用OneBase开发项目中直接$this->前缀+类名 就可以直接当做对象使用。 业务逻辑层也是类似的实现原理,只不过多了验证器等层的识别。 作者建议前缀与目录名称保持一致,比如 $this->logicArticle->getArticleList(); 咱们通过这句代码一看就知道了 是业务逻辑层目录 logic 下的 Article 类。 是不是有点意思哟,这样写代码的过程中就不需要管对象咯,需要的时候就来咯,而且来滴还是非常快。^_^