yii2 源码分析1从入口开始
Posted 小小de细菌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了yii2 源码分析1从入口开始相关的知识,希望对你有一定的参考价值。
我是在 backend 一步步打印的 很多地方我也是很模糊 。后来发现一位大神的文章(http://www.yiichina.com/tutorial/773) 参考文章自己动手开始写的 至于后来的 第一遍 很粗糙 慢慢完善。
希望对自己有帮助 希望各位积极指点 和后面不详细的地方 作补充。 我也会继续完善 。
先从入口开始
$application = new yii\\web\\Application($config); //实例化 Application
$application->run();
这是 Application 的方法
class Application extends \\yii\\base\\Application
在Application类中 首先看有没有构造方法 没有找到 so 就去父类中找(\\yii\\base\\Application)
在\\yii\\base\\Application
.......... public function __construct($config = []) { Yii::$app = $this; // $this 代表 object(yii\\web\\Application) static::setInstance($this); // 在这个方法中把这个类中所有的方法属性都放到一个数组中@@@@@请看下面 $this->state = self::STATE_BEGIN; $this->preInit($config); //看下面有解释 $this->registerErrorHandler($config);//暂不做解释 加载异常类 以后研究 Component::__construct($config); } ..........
@@@@@
public static function setInstance($instance)
{
if ($instance === null) { //$instance不为空 代表的$this(object(yii\\web\\Application))
unset(Yii::$app->loadedModules[get_called_class()]);
} else { //get_class($instance) -> "yii\\web\\Application"
Yii::$app->loadedModules[get_class($instance)] = $instance;
}
}
这样 Yii::$app 就可以调用 该类中的方法 属性 以及父类中的方法。
$this->preInit($config);//
*****preInit****方法
主要是获取到配置文件中的数据 处理配置文件的数据 设置别名等等
public function preInit(&$config)
{
if (!isset($config[\'id\'])) {
throw new InvalidConfigException(\'The "id" configuration for the Application is required.\');
}
if (isset($config[\'basePath\'])) {
$this->setBasePath($config[\'basePath\']); //拿这个做例子
unset($config[\'basePath\']);
。。。部分代码省略。。。。。
public function setBasePath($path)
{
var_dump($path);die; // "/var/www/testyii2/backend"
parent::setBasePath($path); //该方法中设置 $this->_basePath = $app; $app=/var/www/testyii2/backend
Yii::setAlias(\'@app\', $this->getBasePath()); so 此时 @app 就等于 /var/www/testyii2/backend
}
好了现在回到 preInit()方法中
*******end*****
$this->registerErrorHandler($config);简单看下吧
$this->set(\'errorHandler\', $config[\'components\'][\'errorHandler\']);
我打印了下 var_dump($this->get(\'errorHandler\')) 应该是 定义一些错误方法和属性等等 看下图
最后看这个方法
Component::__construct($config); 调用了 object 方法中的 构造方法
object(类):
public function __construct($config = [])
{
if (!empty($config)) {
Yii::configure($this, $config); //找到Yii类 该类中没有configure 方法 然而继承了 baseyii so 去baseyii类中找
//
}
$this->init();
}
。。。。。
//baseyii类
public static function configure($object, $properties)
{
foreach ($properties as $name => $value) {
$object->$name = $value;
}
return $object;
}
//该方法 中 $object ==object类 循环吧配置文件中的 数据 复制给 object对象中的属性和值 最终由于object 是yii\\web\\Application 的最终父类 还有在上面中定义了别名@app
// so 可以Yii::$app->配置参数来访问配置文件中的内容
****end***
分析
$this->init(); 在object类中 class Component extends Object component继承的object
Component::__construct($config); 在base/Application 继承了 Module 类
so 看module 中的init方法()
//module 中的init 方法 public function init() { if ($this->controllerNamespace === null) { //取出控制器命名空间。 $class = get_class($this); if (($pos = strrpos($class, \'\\\\\')) !== false) { $this->controllerNamespace = substr($class, 0, $pos) . \'\\\\controllers\'; } } }
完毕
回到起点 看index.php中的
$application->run(); 在Application类中没有找到run方法 Application 继承 base\\Application类
\\yii\\base\\Application.php 中的run方法
public function run() { try { $this->state = self::STATE_BEFORE_REQUEST; $this->trigger(self::EVENT_BEFORE_REQUEST); ////加载事件函数函数的 $this->state = self::STATE_HANDLING_REQUEST; $response = $this->handleRequest($this->getRequest()); //这里的this调用的是 yii\\web\\Application.php 中的方法看下面
$this->state = self::STATE_AFTER_REQUEST; $this->trigger(self::EVENT_AFTER_REQUEST); //加载事件函数函数的
$this->state = self::STATE_SENDING_RESPONSE; $response->send();
$this->state = self::STATE_END; return $response->exitStatus; }
catch (ExitException $e) {
$this->end($e->statusCode, isset($response) ? $response : null); return $e->statusCode; }
}
//web/Application 中的 handleRequest() public function handleRequest($request) { if (empty($this->catchAll)) { list ($route, $params) = $request->resolve(); //取出路由及参数 } else { $route = $this->catchAll[0]; $params = $this->catchAll; unset($params[0]); } try { Yii::trace("Route requested: \'$route\'", __METHOD__); $this->requestedRoute = $route; $result = $this->runAction($route, $params);//运行控制器中的Acition,下面有详细介绍 base/application 中没有so 找到module 中的runaction()
if ($result instanceof Response) { return $result; } else { $response = $this->getResponse(); if ($result !== null) { $response->data = $result; } return $response; } } catch (InvalidRouteException $e) { throw new NotFoundHttpException(Yii::t(\'yii\', \'Page not found.\'), $e->getCode(), $e); } }
// class Module public function runAction($route, $params = []) { $parts = $this->createController($route);//根据路由创建控制器 看下面
if (is_array($parts)) { /* @var $controller Controller */ list($controller, $actionID) = $parts; $oldController = Yii::$app->controller; Yii::$app->controller = $controller; $result = $controller->runAction($actionID, $params);//创建方法执行控制器里的action actionId ==index( 控制器/index(这里表示方法)) Yii::$app->controller = $oldController; return $result; } else { $id = $this->getUniqueId(); throw new InvalidRouteException(\'Unable to resolve the request "\' . ($id === \'\' ? $route : $id . \'/\' . $route) . \'".\'); } }
$this->createController()
$this->createController() //创建控制器 public function createController($route) { if ($route === \'\') { $route = $this->defaultRoute; } // double slashes or leading/ending slashes may cause substr problem $route = trim($route, \'/\'); if (strpos($route, \'//\') !== false) { return false; } if (strpos($route, \'/\') !== false) { list ($id, $route) = explode(\'/\', $route, 2); } else { $id = $route; $route = \'\'; } echo $route //--->"backend/default/index"
// module and controller map take precedence
if (isset($this->controllerMap[$id])) { //不进入
$controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
return [$controller, $route];
}
$module = $this->getModule($id);
if ($module !== null) { //不进入
return $module->createController($route);
}
if (($pos = strrpos($route, \'/\')) !== false) {
$id .= \'/\' . substr($route, 0, $pos);
$route = substr($route, $pos + 1);
}
//$id = backend/default" (模块/控制器) $route =index 方法
$controller = $this->createControllerByID($id); //下面分析用颜色查找
if ($controller === null && $route !== \'\') { //进入
$controller = $this->createControllerByID($id . \'/\' . $route); // 根据给定的控制器标识创建一个控制器。看下面
$route = \'\';
}
return $controller === null ? false : [$controller, $route];
}
public function createControllerByID($id)
{
$pos = strrpos($id, \'/\');
if ($pos === false) {
$prefix = \'\';
$className = $id;
} else {
$prefix = substr($id, 0, $pos + 1); //backend 模块
$className = substr($id, $pos + 1); //default 控制器
}
if (!preg_match(\'%^[a-z][a-z0-9\\\\-_]*$%\', $className)) {
return null;
}
// preg_match(\'%^[a-z0-9_/]+$%i\', $prefix) ===1
if ($prefix !== \'\' && !preg_match(\'%^[a-z0-9_/]+$%i\', $prefix)) {
return null;
}
$className = str_replace(\' \', \'\', ucwords(str_replace(\'-\', \' \', $className))) . \'Controller\';
$className = ltrim($this->controllerNamespace . \'\\\\\' . str_replace(\'/\', \'\\\\\', $prefix) . $className, \'\\\\\');
if (strpos($className, \'-\') !== false || !class_exists($className)) {
return null;
}
if (is_subclass_of($className, \'yii\\base\\Controller\')) {
$controller = Yii::createObject($className, [$id, $this]); //创建了控制器对象
return get_class($controller) === $className ? $controller : null;
} elseif (YII_DEBUG) {
throw new InvalidConfigException("Controller class must extend from \\\\yii\\\\base\\\\Controller.");
} else {
return null;
}
}
Yii/BaseYii.php
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.\');
} else {
throw new InvalidConfigException(\'Unsupported configuration type: \' . gettype($type));
}
}
****end** 小部分结束(创建控制器部分)
//承接上面的方法继续分析
$controller->runAction($actionID, $params);
namespace yii\\base; //命名空间
class Controller extends Component implements ViewContextInterface{
public function runAction($id, $params = [])
{
$action = $this->createAction($id); ////创建action 暂时不补全代码了 类啊。。。后续补上。
//打印$action == yii\\base\\InlineAction 对象
if ($action === null) {
throw new InvalidRouteException(\'Unable to resolve the request: \' . $this->getUniqueId() . \'/\' . $id);
}
Yii::trace("Route to run: " . $action->getUniqueId(), __METHOD__);
if (Yii::$app->requestedAction === null) {
Yii::$app->requestedAction = $action;
}
$oldAction = $this->action; //NULL
$this->action = $action;
$modules = [];
$runAction = true;
// call beforeAction on modules // 加载默认模块如:Application log等。再调用模块内的beforeAction方法
foreach ($this->getModules() as $module) {
if ($module->beforeAction($action)) {
array_unshift($modules, $module);
} else {
$runAction = false;
break;
}
}
$result = null;
if ($runAction && $this->beforeAction($action)) { //执行beforeAction
// run the action
$result = $action->runWithParams($params); //执行控制器里的action
$result = $this->afterAction($action, $result); //执行afterAction
// call afterAction on modules
foreach ($modules as $module) {
/* @var $module Module */
$result = $module->afterAction($action, $result);
}
}
$this->action = $oldAction;
return $result;
}
}
//打印action yii\\base\\InlineAction
public function runWithParams($params)
{
$args = $this->controller->bindActionParams($this, $params);
Yii::trace(\'Running action: \' . get_class($this->controller) . \'::\' . $this->actionMethod . \'()\', __METHOD__);
if (Yii::$app->requestedParams === null) {
Yii::$app->requestedParams = $args;
}
return call_user_func_array([$this->controller, $this->actionMethod], $args);
}
以上是关于yii2 源码分析1从入口开始的主要内容,如果未能解决你的问题,请参考以下文章