一、实现总览
总结:yii默认将请求参数里面的r(即$_GET['r'])解析成相应的controller和action,并执行。
过程:2个四步走
step1 | step2 | step3 | step4 |
Application->handleRequest() |
Request::resolve() | UrlManage->parseRequest() | 返回[$route,$params],其中$route = $_GET['r'],$params = $_GET; |
Application->handleRequest() |
Application->runAction($route,$params); | 先解析$route=[$controller,$actionID] | 然后$controller->runAction($actionID, $params) |
获取$route,$params
1.入口文件里面执行yii\web\Application::run()时,开始进入路由阶段
2.yii\web\Application里的handleRequest()中的$request->resolve()就是用来解析路由。
list($route, $params) = $request->resolve();//经过后面34的分析,此处$route = $_GET['r'],$params = $_GET;
3.yii\web\Request::resolve方法,实际调用了yii\web\UrlManage的parseRequest方法
$result = Yii::$app->getUrlManager()->parseRequest($this);
4.yii\web\UrlManage::parseRequest方法,此方法默认返回为[$_GET['r'],[]]
拿着$route,$params去执行请求
5.再回到yii\web\Application里的handleRequest()中,执行$this->runAction()
$result = $this->runAction($route, $params);//执行请求
6.runAction()方法的实现
$parts = $this->createController($route);//将$_GET['r']解析为实际的controller和action
list($controller, $actionID) = $parts;
$result = $controller->runAction($actionID, $params);//执行controller里面的action方法
二、详细代码解析
入口文件里面执行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,并执行。