相关文章http://www.tuicool.com/articles/JvM73mn
Yii2.0源码分析之——控制器文件分析(Controller.php)创建动作、执行动作
1yii请求流程
url请求=>application获取request信息,request=>urlManager解析出route,=>Module中根据route来创建controller并处理request。
2
Yii中总共有三种控制器类 base\Controller.php 这个是下面两个的基类 console\Controller.php 这个是控制台控制器 web\Controller.php 这个是web控制器
1、和action相关的函数
执行路由:public function run($route, $params = [])
/* * route值即可以为当前controller中的action id, * * 也可为module id/controller id/action id/这种格式 * 如果以“/”开头,将于application来处理,否则,用控制器所属模块来处理 */
public function run($route, $params = []) { //先判断route中有没有“/” $pos = strpos($route, '/'); if ($pos === false) { //如果没有“/”,则为action id,直接调用runAction来执行这个action。如:index return $this->runAction($route, $params); } elseif ($pos > 0) { //如果“/”在中间,由当前的模块来处理这个route。如:test/index return $this->module->runAction($route, $params); } else { //如果以“/”开头,则用当前的应用程序来处理这个route。如:/test/index; return Yii::$app->runAction(ltrim($route, '/'), $params); } }
执行动作:public function runAction($id, $params = [])
/* * $id 为action的id,如定义的actionIndex,那么id就为Index。 * */ public function runAction($id, $params = []) { //创建action $action = $this->createAction($id); 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; /* * 获取当前控制器的所以的模块,并执行每个模块的beforeAction来检查当前的action是否可以执行, * 注意:getModules返回的数组顺序为:从父模块到子模块, * 所以在执行beforeAction的时候,先检查最外层的父模块,然后检查子模块。 * * 然而在执行afterAction的时候,顺序就反过来了,先执行子模块,最后执行父模块。 * */ foreach ($this->getModules() as $module) { if ($module->beforeAction($action)) { array_unshift($modules, $module); } else { $runAction = false; break; } } $result = null; //如果所以的父模块都满足执行的条件 if ($runAction) { /* * 再判断当前控制器中是beforeAction, * 最后由生成的action对象来执行runWithParams方法 * * 执行完后,再执行afterAction方法 */ if ($this->beforeAction($action)) { $result = $action->runWithParams($params); $result = $this->afterAction($action, $result); } } //执行所有父模块的afterAction foreach ($modules as $module) { /** @var Module $module */ $result = $module->afterAction($action, $result); } $this->action = $oldAction; return $result; }
创建动作 public function createAction($id)
//由action id来创建action对象 public function createAction($id) { //使用默认的action id ,默认值为:index if ($id === '') { $id = $this->defaultAction; } $actionMap = $this->actions(); if (isset($actionMap[$id])) { //如果在actions方法中指定了独立的动作,则直接使用此动作。 return Yii::createObject($actionMap[$id], [$id, $this]); } elseif (preg_match('/^[a-z0-9\\-_]+$/', $id) && strpos($id, '--') === false && trim($id, '-') === $id) { /* * action id由:a到z、0到9、\、-、_ 这五种字符组成, * 并且不能包含“--” * 并且不能以“-”为开头或结尾 * * 先以“-”把id分隔为数组,再以“ ”连接到字符串,把每个单词首字母大写,最后把“ ”去掉,并和"action"连接 * 如; * 1、new-post-v-4 * 2、['new','post','v','4'] * 3、new post v 4 * 4、New Post V 4 * 5、NewPostV4 * 6、actionNewPostV4 */ $methodName = 'action' . str_replace(' ', '', ucwords(implode(' ', explode('-', $id)))); if (method_exists($this, $methodName)) { /* * 如果当前控制器中存在这个actionXXX方法, * 再通过反射生成方法,再次检查一遍,最后生成InlineAction */ $method = new \ReflectionMethod($this, $methodName); if ($method->getName() === $methodName) { return new InlineAction($id, $this, $methodName); } } } return null; }