yii2源码(1)--执行流程
来源:互联网 发布:淘宝店铺设计师申请 编辑:程序博客网 时间:2024/04/24 01:36
转载自:http://www.yiichina.com/code/546
Yii2底层分析
我是从入口处分析的。
$mysiteRoot/frontend
首先:$mysiteRoot/frontend/index.php
$application = new yii\web\Application($config);//先从这入手$application->run();//先不急,后面会提到
从上面注释的位置入口
$config为配置文件,这里我们来看看是如何加载配置文件内容的。
顺着application我们能找到:yii\web\Application.php
class Application extends \yii\base\Application
yii\web\Application.php中没有构造函数,所以我们顺理成章的找找
它的父类也就是\yii\base\Application,看看父类里面是否有构造函数
\yii\base\Application没有让我们失望,
构造方法如下:
abstract class Application extends Module{.....public function __construct($config = []){ Yii::$app = $this; $this->setInstance($this);//将\yii\base\Application中的所有的属性和方法交给Yii::$app->loadedModules数组中 $this->state = self::STATE_BEGIN;
// 设置要加载的components,放在$config数组中 $this->preInit($config);//加载配置文件的框架信息 如:设置别名,设置框架路径等等 最为重要的是给加载默认组件 $this->registerErrorHandler($config);//加载配置文件中的异常组件 Component::__construct($config);//将配置文件中的所有信息赋值给Object,也就是Yii::$app->配置文件参数可以直接调用配置文件的内容 如:Yii::$app->vendorPath//输出框架路径 Yii::$app->components['redis']//输出redis配置信息}......
下面我们来分析下面的代码
首先是:Yii::$app = $this;
这一句指的是,将\yii\base\Application里所有的公共方法都交给了,Yii::$app,其实Yii大部分信息都在Yii::$app变量中
当然也包括它的父类如:\yii\base\Module \yii\di\ServiceLocator \yii\base\Component \yii\base\Object
$this->setInstance($this);//module里会用到,为getInstance提供
这一句是指向\yii\base\Module
public static function setInstance($instance)//module模块里会用到,为getInstance提供{ if ($instance === null) { unset(Yii::$app->loadedModules[get_called_class()]); } else { Yii::$app->loadedModules[get_class($instance)] = $instance; }}
这句意思是:将当前类名和存储类的对象变量加入Yii::$app->loadedModules['yii\web\Application']数组中
这样直接通过Yii::$app->loadedModules['yii\web\Application']就可以直接调用这个类
重要的用处在于后面的使用如:
在Module里,也就是module使用的时候,可以通过self::getInstance()获取App对象,类似于Yii::$app。这个研究的比较浅,以后再深入,有疑问的童鞋可以深入
Yii::$app = $this;$this->setInstance($this);
这两句做的操作是一样的,其实是有所不同的。
Yii::$app = $this;
指的是通过Yii::$app可以调用yii\web\Application及其父类所有的方法
Yii::$app->loadedModules['yii\web\Application']//也能同样做到
loadedModules是一个数组,存放成员类的。它除了能调用当前,还能调用其它许许多多的类....
$this->preInit($config);
这一句是将配置文件中的一些变量设置别名,主要是针对路径、URL之类的
preInit方法解析:
public function preInit(&$config) { ..................... // 有一些核心组件是必须加载的,将用户要加载的组件和必须加载的核心组件放到同一个数组里面,便于后期加载 // merge core components with custom components foreach ($this->coreComponents() as $id => $component) { if (!isset($config['components'][$id])) { $config['components'][$id] = $component; } elseif (is_array($config['components'][$id]) && !isset($config['components'][$id]['class'])) { $config['components'][$id]['class'] = $component['class']; } } }
$this->registerErrorHandler($config);
加载异常处理,这块比较深就先不研究了,觉得比较浅的童鞋可以接着补充哈
Component::__construct($config);
这一句指向Object
public function __construct($config = []){
// 由于这个方法是在yii2\base\Application中调用的,所有$this应该为yii2\base\Application if (!empty($config)) { Yii::configure($this, $config);//将配置文件里面的所有配置信息赋值给yii2\base\Application }
// 调用yii2\base\Application中的init方法 $this->init();//下面会细分析}
yii2\base\Application中的init方法:
public function init() { $this->state = self::STATE_INIT; // 加载config文件中的extensions和bootstrap部分 $this->bootstrap(); }
这个就是把当前的配置文件config变量中内容交给Object 再就是讲components默认需要加载的组件类,赋到config配置文件变量中。
Object是基础类,所以绝大部分类都能直接调用配置文件中配置内容
如:
var_dump(Yii::$app->name);
实际上config文件的数组中有name属性
return [ 'id' => 'app-frontend', 'name' => '环球在线',......
再回到Object
public function __construct($config = []){ if (!empty($config)) { Yii::configure($this, $config); }// 这以上已经执行完了 $this->init();}
至此第一部分执行完了,再看第二部分吧
$application = new yii\web\Application($config);//分析完成$application->run();//加载主要组件,运行默认控制器
接下拆分 $application->run吧
用ide指向直接到了\yii\base\Application.php
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->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; }} $response = $this->handleRequest($this->getRequest());
摘出来的这句:
$this->getRequest()//获取Request对象
这个没啥可说的,获取Request对象
$this->handleRequest($this->getRequest());
通过指向\yii\web\Application.php
public function handleRequest($request){ if (empty($this->catchAll)) { list ($route, $params) = $request->resolve();//取出路由及参数,下节再具体分析(调用了urlManager组件) } 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,下面有详细介绍 if ($result instanceof Response) { return $result; } else { $response = $this->getResponse();/*这个是加载yii\base\Response类,在外部可以Yii::$app->get('response')、Yii::$app->getResponse()、Yii::$app->response 等等方式来加载response类,主要用来加载http状态,及头信息,如301,302,404,ajax头等等的获取*/ if ($result !== null) { $response->data = $result; } return $response; } } catch (InvalidRouteException $e) { throw new NotFoundHttpException(Yii::t('yii', 'Page not found.'), $e->getCode(), $e); }}
我们再看看这句指向:\yii\base\Module.php
public function runAction($route, $params = []){ $parts = $this->createController($route);//根据路由创建控制器 if (is_array($parts)) { /* @var $controller Controller */ list($controller, $actionID) = $parts;//获得$actionId和$controller $oldController = Yii::$app->controller; Yii::$app->controller = $controller; $result = $controller->runAction($actionID, $params);//运行使用控制器加载 action方法 Yii::$app->controller = $oldController;//将对象交给Yii::$app->controller 这里面起的作用应该是运行控制器,最后释放控制器的对象变量 return $result; } else { $id = $this->getUniqueId(); throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".'); }}
Module里有一段:
$controller = Yii::createObject($this->controllerMap[$id], [$id, $this]);
其实在
$this->createController($route)
这个时候创建了控制器对象
下面看看如何加载action的。
$result = $controller->runAction($actionID, $params);//运行使用控制器加载 action方法
上面这句指向:
public function runAction($id, $params = []){ $action = $this->createAction($id);//创建action 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; $this->action = $action; $modules = []; $runAction = true; // 加载默认模块如: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;} $result = $action->runWithParams($params);//执行控制器里的action
这里才是真正执行action的地方
首先弄清楚$action是什么类?这里可以var_dump一下就清楚了,刚开始我也被编辑器迷糊了找半天
$action类是yii\base\InlineAction
public function runWithParams($params){ $args = $this->controller->bindActionParams($this, $params);//对action的参数进行分析,并且赋值给控制器 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);//用控制器类去执行action方法,并且带上参数。}
本人使用的ide是phpstorm。顺着index.php的入口一步步读代码,可能有些地方分析不太完整,以后会慢慢补充的
- yii2源码(1)--执行流程
- mybatis源码解析-----执行流程1
- yii2底层源码分析1
- yii2源码(2)--路由
- redis执行流程源码分析
- struts2执行流程源码分析
- Struts2执行流程源码解析
- tinyhttpd源码阅读(1)——服务器执行流程
- Tor源码分析三 -- 客户端执行流程(初始化)
- Tor源码分析五 -- 客户端执行流程(libevent调度)
- Tor源码分析八 -- 客户端执行流程(second_elapsed_callback函数)
- QUnit源码阅读(2):test基本执行流程
- QUnit源码阅读(3):asyncTest基本执行流程
- Google test源码阅读(一):基本执行流程
- Zookeeper源码分析(3)- Leader执行流程
- Zookeeper源码分析(4)- Follower执行流程
- Android源码解析(二十五)-->onLowMemory执行流程
- scrapy源码分析(一)---------------------总执行流程概览
- Aizu 2224 Save your cats(最大生成树)
- 关于Spring中的<context:annotation-config/>配置
- QT 之 插件自定义编写
- CAS原理
- Spring boot中的属性配置文件小结
- yii2源码(1)--执行流程
- NavigationView+DrawerLayout实现侧滑栏效果
- C#小项目之登录界面1
- CSS margin 属性
- Spring-boot + atomikos + druid分布式事务配置
- C# 逆变与协变
- OPC UA --open62541学习
- AlertDialog用法
- std::set, std::list, std::vector在erase的区别