# yii2-source-doc **Repository Path**: jackcipher/yii2-source-doc ## Basic Information - **Project Name**: yii2-source-doc - **Description**: yii2 源码分析 (持续更新) - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-03-09 - **Last Updated**: 2020-12-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #### 1 主流程 ### ![image-20200306174635931](./README.assets/image-20200306174635931.png) #### 2 核心类SPL注册 ![image-20200306100512832](./README.assets/image-20200306100512832.png) ``` Yii.php文件 class Yii extends \yii\BaseYii { } spl_autoload_register(['Yii', 'autoload'], true, true); Yii::$classMap = require __DIR__ . '/classes.php'; Yii::$container = new yii\di\Container(); ``` ```php public static function autoload($className) { if (isset(static::$classMap[$className])) { $classFile = static::$classMap[$className]; if ($classFile[0] === '@') { $classFile = static::getAlias($classFile); } } elseif (strpos($className, '\\') !== false) { $classFile = static::getAlias('@' . str_replace('\\', '/', $className) . '.php', false); if ($classFile === false || !is_file($classFile)) { return; } } else { return; } include $classFile; if (YII_DEBUG && !class_exists($className, false) && !interface_exists($className, false) && !trait_exists($className, false)) { throw new UnknownClassException("Unable to find '$className' in file: $classFile. Namespace missing?"); } } ``` Yii 类在此处主要为了对核心Class完成自动加载注册,当找不到定义得类时,会在 [Yii, autoload] 中查找,并被 include 进来。index.php 中得 ArrayHelper 也是在此处加载的。 vendor/yiisoft/yii2/classes.php 中定义了需要被自动加载得 Class. #### 3. 配置文件加载 ~~~php $config = yii\helpers\ArrayHelper::merge( require __DIR__ . '/../../common/config/main.php', require __DIR__ . '/../../common/config/main-local.php', require __DIR__ . '/../config/main.php', require __DIR__ . '/../config/main-local.php' ); (new yii\web\Application($config))->run(); ~~~ index.php 中通过获取 common 模块和当前模块得配置,并通过 ArrayHelper 完成递归merge.这里需要注意得是配置文件的优先级。如果 common 和 web 中均有相同的配置,该配置会被 web 中的配置所覆盖。 #### 4. web 应用的泛化关系 ![image-20200306201048181](./README.assets/image-20200306201048181.png) yii\web\Application 没有构造函数,它的构造函数来自 yii\base\Application. #### 4. yii\web\Application 实例化 ~~~php public function __construct($config = []) { Yii::$app = $this; static::setInstance($this); $this->state = self::STATE_BEGIN; $this->preInit($config); $this->registerErrorHandler($config); Component::__construct($config); } ~~~ 入口文件中调用的 new yii\web\Application($config) 来源于 base\Application. 如上代码所示,web\Application 实例化时,首先将 Yii::$app 指向 web\Application. 这个变量在实际开发中经常会用到,它所代表的含义,就是 web\Application 本身.后面会讲到如何通过 Yii::$app 获取配置文件中的组件。 接着,会加载错误处理组件并完成PreInit方法。PreInit方法不仅完成了路径的设置,时区的设置,容器设置。更重要的是完成了核心组件的加载。 ##### 4.1 核心组件加载 ~~~php public function coreComponents() { return [ 'log' => ['class' => 'yii\log\Dispatcher'], 'view' => ['class' => 'yii\web\View'], 'formatter' => ['class' => 'yii\i18n\Formatter'], 'i18n' => ['class' => 'yii\i18n\I18N'], 'mailer' => ['class' => 'yii\swiftmailer\Mailer'], 'urlManager' => ['class' => 'yii\web\UrlManager'], 'assetManager' => ['class' => 'yii\web\AssetManager'], 'security' => ['class' => 'yii\base\Security'], ]; } ~~~ 核心组件主要有以上几种,与其说是核心组件加载,不如说是核心组件缺省处理。这是因为,如果用户配置文件中定义了以上8种组件,那么就会优先使用用户配置的组件。如果用户没有配置这些组件,那么PreInit就会将缺失的组件补充到 $config 数组,传递给下游环节。 ##### 4.2 特殊构造函数 ~~~php class A { public $name = 'a'; function __construct() { echo $name; } } class B { public name = 'b'; function __construct() { parent::__construct(); } } ~~~ ~~~php class A { public $name = 'a'; function __construct() { echo $name; } } class B extends A { public $name = 'b'; function __construct() { echo 'empty'; } } class C extends B { public $name = 'c'; function __construct() { A::__construct(); } } ~~~ 继承父类,在子类中调用父类构造函数比较常见。跨父类的构造函数与parent::__construct 方式类似,继承跨父类的构造函数。 #### Web 入口分析 1. index.php 引入composer, Yii, 配置文件, Web应用运行 2. Yii.php Yii 初始化 加载核心classes 文件 3. 配置文件递归合并 4. yii\base\Application 完成预初始化、注册错误处理器,并实现组件构造 5. Component类没有构造函数,调用父类BaseObject的构造函数,完成配置文件加载,并将配置文件中的components 挂载到 Yii::$app 6. yii\base\Application 调用 run 方法。 7. run方法完成事件触发和handleRequest 8. handleRequest 完成异常捕捉,请求路由和参数获取,并执行runAction 9. runAction 由 Modele 模块实现,首先根据请求路由创建控制器 ![image-20200306145528768](./README.assets/image-20200306145528768.png)