yii2 route路由源码实现原理的深度解析

一、实现总览

总结: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,并执行。

猜你喜欢

转载自blog.csdn.net/wuhuagu_wuhuaguo/article/details/105212642
今日推荐