- 首发于 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'));
}
}
初始化路由类调用Typecho_Router::setRoutes($options->routingTable);
得到所有的路由表
路由解析器
不存在 $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;
}
}
}