typecho源码阅读-路由部分

  • 首发于 https://blog.lou00.top/index.php/archives/11/

路由表初始化

从入口文件index.php开始
首先Typecho_Widget::widget('Widget_Init');
跟进发现在\var\Widget\Widget_Options::execute()自动初始化路由表

    public function execute()
    {
        $this->db->fetchAll($this->db->select()->from('table.options')
        ->where('user = 0'), array($this, 'push'));
        /* 从数据库中取出,其中有序列化的routeTable */
        ...
        /** 自动初始化路由表 */
        $this->routingTable = unserialize($this->routingTable);
        if (!isset($this->routingTable[0])) {
            /** 解析路由并缓存 */
            /* 
            不存在 this->routingTable[0] 时,
            通过路由解析器来构造规则,并把其存入数据库中
            */
            $parser = new Typecho_Router_Parser($this->routingTable);
            $parsedRoutingTable = $parser->parse();
            $this->routingTable = array_merge(array($parsedRoutingTable), $this->routingTable);
            $this->db->query($this->db->update('table.options')->rows(array('value' => serialize($this->routingTable)))
            ->where('name = ?', 'routingTable'));
        }
    }

image.png

初始化路由类调用Typecho_Router::setRoutes($options->routingTable);
得到所有的路由表

image.png

路由解析器

不存在 $this->routingTable[0]
可以促发Typecho_Router_Parser($this->routingTable);,
至于啥时候不存在 $this->routingTable[0],有多种情况存在,可以全局搜索routingTable\[0\]查看unset函数
接下来看\var\Typecho\Router\Parser.php

//先初始化
public function __construct(array $routingTable)
    {
        $this->_routingTable = $routingTable;

        $this->_defaultRegx = array(
            'string' => '(.%s)',
            'char'   => '([^/]%s)',
            'digital'=> '([0-9]%s)',
            'alpha'  => '([_0-9a-zA-Z-]%s)',
            'alphaslash'  => '([_0-9a-zA-Z-/]%s)',
            'split'  => '((?:[^/]+/)%s[^/]+)',
        );
    }
//定义路由规则
public function parse()
    {
        $result = array();

        foreach ($this->_routingTable as $key => $route) {
            $this->_params = array();
            $route['regx'] = preg_replace_callback("/%([^%]+)%/", array($this, '_match'),
            preg_quote(str_replace(array('[', ']', ':'), array('%', '%', ' '), $route['url'])));

            /** 处理斜线 */
            $route['regx'] = rtrim($route['regx'], '/');
            $route['regx'] = '|^' . $route['regx'] . '[/]?$|';

            $route['format'] = preg_replace("/\[([^\]]+)\]/", "%s", $route['url']);
            $route['params'] = $this->_params;

            $result[$key] = $route;
        }

        return $result;
    }

然后通过\var\Widget\Widget_Options::execute()更新数据库

路由分发

index.php里调用Typecho_Router::dispatch();
http://..../index.php/archives/1/为例

public static function dispatch()
    {
        /** 获取PATHINFO */
        $pathInfo = self::getPathInfo();
        /* 
           $_routingTable 路由表在上述步骤中获得
           每个路由都有一个自己的路由规则 ,$route['regx']
           不满足直接返回flase
        */
        foreach (self::$_routingTable as $key => $route) {
            if (preg_match($route['regx'], $pathInfo, $matches)) {
                self::$current = $key;

                try {
                    /** 载入参数 */
                    $params = NULL;

                    if (!empty($route['params'])) {
                        unset($matches[0]);
                        $params = array_combine($route['params'], $matches);
                    }
                    /* $params = {'cid':'1'}  */
                    $widget = Typecho_Widget::widget($route['widget'], NULL, $params);
                    /* 通过这条获得文章内容 */
                    if (isset($route['action'])) {
                        $widget->{$route['action']}();
                    }
                    /*
                      $route['action'] = 'render'
                      此步获取模板
                    */
                    Typecho_Response::callback();
                    return;

                } catch (Exception $e) {
                    if (404 == $e->getCode()) {
                        Typecho_Widget::destory($route['widget']);
                        continue;
                    }

                    throw $e;
                }
            }
        }

你可能感兴趣的:(typecho源码阅读-路由部分)