当从容器中get一个类的实例时,容器Container需要解决的一个问题是依赖。
比如从容器中获取类A的实例,假如说类A依赖于类B,那么容器需要先获得B的实例,再实例化A。更多的依赖以此类推。
那么Yii是如何实现自动实例化依赖类的呢?
protected function getDependencies($class) { //......... $dependencies = []; $reflection = new ReflectionClass($class); $constructor = $reflection->getConstructor(); if ($constructor !== null) { foreach ($constructor->getParameters() as $param) { if (version_compare(PHP_VERSION, '5.6.0', '>=') && $param->isVariadic()) { break; } elseif ($param->isDefaultValueAvailable()) { $dependencies[] = $param->getDefaultValue(); } else { $c = $param->getClass(); $dependencies[] = Instance::of($c === null ? null : $c->getName()); } } } //........ return [$reflection, $dependencies]; }
1、获得构造函数 $reflection->getConstructor();
2、获取构造函数的参数 $constructor->getParameters();
3、如果参数不是可变参数(Variadic), 假如有默认值,那么就把默认值加入到dependencies数组中;如果没有默认值,那么就获取这个参数的类名 $param->getClass() (如果参数不是一个类,则返回null),然后不管是null还是具体的类名,都返回一个Instance类实例,这个Instance实例有一个属性id,值是$param->getClass();
4、返回dependencies数组,这个数组由我们要获取的类的构造函数的参数的默认值、参数的类名、null组成。顺序跟构造函数参数的顺序对应,因为如果你从容器中获取类的实例,如果传入$params,则依赖就改变了,以你传入的参数为准了。所以后面有一个覆盖的步骤。这个传入的$params为一个数组,里面是要传给构造函数的参数。
5、这就是覆盖咯
foreach ($params as $index => $param) { $dependencies[$index] = $param; }