Yii依赖注入容器图解

1、注册类定义

set($class, $definition = [], array $params = [])注册类定义到容器中normalizeDefinition($class, $definition)对类的定义信息进行规范化处理参数解析:1、$class:类的标识,可以是类名、接口名、别名2、$definition: 对于$class的定义,其类型可以是: php匿名函数、实例对象、数组、字符串:类名、接口名、别名3、$params: 类的构造函数参数列表功能解析:1、调用 normalizeDefinition($class, $definition)将类的定义进行规划化处理后存储到$this->_definitions[$class]中2、将类的构造函数参数存储到$this->_params[$class]中3、$this->_singletons存储的是类的实例,如果重新注册类定义,原实例将被销毁功能解析:1、如果$definition为空,返回 [‘class’ => $class]2、如果$definition为字符串,返回 [‘class’ => $definition]3、如果 $definition为php匿名函数或实例对象,不做处理,原样返回4、如果 $definition为数组 (1)包含class元素,不做处理原样返回 (2)不包含class元素 判断$class是否为有效类 不是有效类直接抛异常 是有效类,则设置$definition[‘class’] = $class 然后返回$definition 最终 $definition的值只能是: 带有“class”元素的数组、匿名函数、实例对象

2、获取类实例

get($class, $params = [], $config = [])获取类的实例根据类的定义的不同,做相应处理:1:匿名函数:利用call_user_func直接调用此函数,返回结果对象实例2、对象:直接返回3、数组:调用build方法获取类实例(此处如果$class与类定义信息中class属性值不相同,会递归调用get()方法本身,直到两者相同或者该类定义时,才调用build获取类实例)4、没有该类定义:直接调用build方法或类实例获取类实例后会先存储到$this->_singletons[$class]中,再返回build($class, $params, $config)创建类的实例getDependencies($class)获取类的依赖信息1、调用 getDependencies($class) 获取类的依赖信息2、调用resolveDependencies($dependencies, $reflection)解析类的依赖信息3、通过 $reflection->isInstantiable() 判断类是否可以实例化,如果不能则抛异常4、通过 $reflection->newInstanceArgs($dependencies) 创建类的实例 (1) 如果$config为空,直接根据$dependencies参数创建类的实例 if (empty($config)) { return $reflection->newInstanceArgs($dependencies); } (2)$config不为空,并且$dependencies不为空,并且类实现了接口yii\base\Configurable 则将$config作为最后一个参数 if (!empty($dependencies) && $reflection->implementsInterface(‘yii\base\Configurable’)) { $dependencies[count($dependencies) - 1] = $config; return $reflection->newInstanceArgs($dependencies); } 实现接口yii\base\Configurable的类应该实现支持通过构造函数的最后一个参数设置他的属性 例如yii\base\Object类构造函数的实现 (3)如果$config为空,并且 $dependencies为空 或者类没有实现接口yii\base\Configurable 则创建类的实例后,循环将$config中元素设置为该实例的属性的值 $object = $reflection->newInstanceArgs($dependencies); foreach ($config as $name => $value) { $object->$name = $value; } return $object; resolveDependencies($dependencies, $reflection)解析类的依赖信息1、通过php反射机制获取类的有关信息(存储到$reflection) $reflection = new ReflectionClass($class);2、通过类的构造函数参数了解类的依赖信息 循环处理构造函数参数 (1)如果参数有默认值,直接存到$dependencies[]中 有默认值说明是简单数据类型 (2)如果参数没有默认值, $c = $param->getClass(); $dependencies[] = Instance::of($c === null ? null : $c->getName()); 根据php手册得知: 如果$param是简单数据类型的话$param->getClass()返回null 如果$param是类类型的话$param->getClass()->getName()返回类名 Instance类中of方法的实现: public static function of($id) { return new static($id); } 通过以上分析得知:如果参数没有默认值,我们创建了Instance实例存到dependencies[]中 3、返回 $reflection, $dependencies对$dependencies,$reflection中的缓存信息作进一步处理:1、将依赖信息中保存的Instance实例所引用的类进行实例化,重新存储到$dependencies中(通过递归调用get()方法获取依赖类实例) 2、返回$dependencies