yii\web\Application->yii\base\Application->yii\base\Module->yii\di\ServiceLocator->yii\base\Component->yii\base\Object->yii\base\Configurable
yii->yii\BaseYii,继承的来源
Yii.php
require(__DIR__ . '/BaseYii.php');
/**
* Yii is a helper class serving common framework functionalities.
*
* It extends from [[\yii\BaseYii]] which provides the actual implementation.
* By writing your own Yii class, you can customize some functionalities of [[\yii\BaseYii]].
*
* @author Qiang Xue
* @since 2.0
*/
class Yii extends \yii\BaseYii
{
}
最顶类是接口类型Configurable,如下:
interface Configurable{
}
数据库连接组件分析:
yii\db\Connection 是继承yii\base\Component,为什么要继承Component呢?
解答:因为Component有__set函数,
1、将组件配置参数components数组通过setComponents()函数转化为组件对象集合
入口文件分析:
index.php
$config = yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../../../core/common/config/main.php'),
...
);
$application = new yii\web\Application($config);
namespace yii\base
Application.php
public function __construct($config = [])
{
/*..*/
Component::__construct($config);
}
Component继承yii\base\Object构造函数并执行
namespace yii\baseObject.php
public function __construct($config = [])
{
if (!empty($config)) {
Yii::configure($this, $config);
}
..
}
这里的$this是yii\web\Application实例
Yii继承BaseYii,并且执行configure的函数
namespace yii;
BaseYii.php文件
public static function configure($object, $properties)
{
foreach ($properties as $name => $value) {
$object->$name = $value;
}
return $object;
}
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
// set property
$this->$setter($value);
return;
} }
这里的$name='components'
$value=组件配置参数:
因为构造函数里面的$value = common\config\main.php的如下信息
'component' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn'=>'mysql:dbname=mhk;host=127.0.0.1',
'username'=>'root',
'password'=>'password'
]
];
setComponents()函数:设置各个组件的参数为value,各个组件的名字为key,保存在
$this->_definitions变量里
ServiceLocator.php
namespance yii\di
public function setComponents($components)
{
foreach ($components as $id => $component) {
$this->set($id, $component);
}
}
yii::$app->db的会后会调用yii\di\ServiceLocator的__get()
public function __get($name)
{
if ($this->has($name)) {
return $this->get($name);
} else {
return parent::__get($name);
}
}
public function get($id, $throwException = true)
{
if (isset($this->_components[$id])) {
return $this->_components[$id];
}
if (isset($this->_definitions[$id])) {
$definition = $this->_definitions[$id];
if (is_object($definition) && !$definition instanceof Closure) {
return $this->_components[$id] = $definition;
} else {
return $this->_components[$id] = Yii::createObject($definition);
}
} elseif ($throwException) {
throw new InvalidConfigException("Unknown component ID: $id");
} else {
return null;
}
}
Yii::createObject($definition)这个就是为各个组件根据配置的参数来创建各个组件对象,并保存到$this->_components变量
下次再调用yii::$app->db时候就直接从这个变量取到了
public function has($id, $checkInstance = false)
{
return $checkInstance ? isset($this->_components[$id]) : isset($this->_definitions[$id]);
}
至于创建对象的方法createObject()
public static function createObject($type, array $params = [])
{
if (is_string($type)) {
return static::$container->get($type, $params);
} elseif (is_array($type) && isset($type['class'])) {
$class = $type['class'];
unset($type['class']);
return static::$container->get($class, $params, $type);
} elseif (is_callable($type, true)) {
return static::$container->invoke($type, $params);
} elseif (is_array($type)) {
throw new InvalidConfigException('Object configuration must be an array containing a "class" element.');
}
throw new InvalidConfigException('Unsupported configuration type: ' . gettype($type));
}
用容器去获取对象的,容器的概念就是依赖注入了。就是利用反射机制的构造函数参数注入原理
$reflectionClass = new ReflectionClass("Bar");
return $reflectionClass->newInstanceArgs(array($this, $this->arr));