Yii2源码学习之路由实现
入口文件里面执行yii\web\Application::run()时,开始进入路由阶段
1.yii\web\Application里的handleRequest方法中的$request->resolve()就是用来解析路由。
public function handleRequest($request) { if (empty($this->catchAll)) {//catchAll用于拦截所有请求,默认不拦截 list ($route, $params) = $request->resolve();//经过后面的分析,此处$route = $_GET['r'],$params = $_GET; } else {//拦截后替代的请求配置在catchAll里面 $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);//执行请求 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); } }
2.接下来我们具体分析一下yii\web\Request::resolve方法
public function resolve() { $result = Yii::$app->getUrlManager()->parseRequest($this);//实际调用了yii\web\UrlManage的parseRequest方法,看下面的分析$result = [$_GET['r'],[]] if ($result !== false) { list ($route, $params) = $result;//$route = $_GET['r'],$params = [] if ($this->_queryParams === null) { $_GET = $params + $_GET; // preserve numeric keys } else { $this->_queryParams = $params + $this->_queryParams; } return [$route, $this->getQueryParams()];//return [$_GET['r'],$_GET] } else { throw new NotFoundHttpException(Yii::t('yii', 'Page not found.')); } }
3.yii\web\UrlManage::parseRequest方法
public function parseRequest($request) { if ($this->enablePrettyUrl) {//默认enablePrettyUrl为false,这里面是pretty url方式的解析工作,不做分析 $pathInfo = $request->getPathInfo(); /* @var $rule UrlRule */ foreach ($this->rules as $rule) { if (($result = $rule->parseRequest($this, $request)) !== false) { return $result; } } if ($this->enableStrictParsing) { return false; } Yii::trace('No matching URL rules. Using default URL parsing logic.', __METHOD__); $suffix = (string) $this->suffix; if ($suffix !== '' && $pathInfo !== '') { $n = strlen($this->suffix); if (substr_compare($pathInfo, $this->suffix, -$n, $n) === 0) { $pathInfo = substr($pathInfo, 0, -$n); if ($pathInfo === '') { // suffix alone is not allowed return false; } } else { // suffix doesn't match return false; } } return [$pathInfo, []]; } else { Yii::trace('Pretty URL not enabled. Using default URL parsing logic.', __METHOD__); $route = $request->getQueryParam($this->routeParam, '');//$this->routeParam默认为r,这里实际上是$route = $_GET['r']; if (is_array($route)) { $route = ''; } return [(string) $route, []];//所以此方法默认返回为[$_GET['r'],[]] } }
4.执行请求,yii\base\Module::runAction
public function runAction($route, $params = []) { $parts = $this->createController($route);//将$_GET['r']解析为实际的controller和action if (is_array($parts)) { /* @var $controller Controller */ list($controller, $actionID) = $parts; $oldController = Yii::$app->controller; Yii::$app->controller = $controller; $result = $controller->runAction($actionID, $params);//执行controller里面的action方法 Yii::$app->controller = $oldController; return $result; } else { $id = $this->getUniqueId(); throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".'); } }
综合以上方法,yii默认将请求参数里面的r(即$_GET['r'])解析成相应的controller和action,并执行