thinkphp5 源码分析之二 路由解析

今天啃关于路由解析的部分,感觉这块还是挺复杂的;有的点还是没看透,把看明白的总结出来。

路由解析的流程

我们在使用路由解析的时候,很多部分参与了路由解析,远不止tp框架如下图
thinkphp5 源码分析之二 路由解析_第1张图片
可以看出从客户端发起到服务器处理响应,经理的4个阶段,tp框架只是其中一部分。

路由的意义

url作为一种输入的数据,过路由解析,
匹配到应用业务控制器(也有可能是闭包函数和自定义的类)

路由相关的参数~~~~

thinkphp5 源码分析之二 路由解析_第2张图片
path_info字符串标志,path_info兼容内容,path_info分隔符
'var_pathinfo' => 's',
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
'pathinfo_depr' => '/',
系统变量request_uri,系统变量base_url
'url_request_uri' => 'REQUEST_URI',
'base_url' => $_SERVER["SCRIPT_NAME"],
伪静态后缀,普通方式参数?,禁止访问后缀
'url_html_suffix' => '.html',
'url_common_param' => false,
'url_deny_suffix' => 'ico|png|gif|jpg',

路由开启与关闭,强制路由开启与关闭,模块映射
'url_route_on' => true,
'url_route_must' => false,
'url_module_map' => [],
域名部署开启与关闭,根域名
'url_domain_deploy' => false,
'url_domain_root' => '',
控制器自动转换开启与关闭,操作自动转换开启与关闭
'url_controller_convert' => true,
'url_action_convert' => true,
// 按照顺序解析变量
'url_param_type' => 1,
//路由配置文件,可配置多个
'route_config_file' => ['route'],

路由注册

这里只简单举两个栗子,想知道更详细请查阅thinkphp5.0官方手册毕竟这里我们是以分析源码为主。
thinkphp5 源码分析之二 路由解析_第3张图片

源码解析

我将tp5的路由解析是将我们配置文件中配置的路由规则注册进thinkRoute.php的私有静态变量$rules,本质上来说检验路由就是按规则将$rules中的信息进行校验, 所以为了便于理解,我将讲述分为两部分, 一部分是路由注册, 一部分是路由解析;下面将会根据这两部分进行分析。

路由注册

整个过程如下图
thinkphp5 源码分析之二 路由解析_第4张图片
入口
app::run==>app::routeCheck===>route::import
在routeCheck中会检查是否开启路由缓存,同时会去RUNTIME_PATH下查找是否有缓存的路由文件,如果没有引入文入路由文件,在本例中即是route .php 当引入

thinkphp5 源码分析之二 路由解析_第5张图片

会执行其中标红的部分,返回的数组,会执行Route::import 方法,而在注册路由的过程中除了分组路由以外(我们另外分析),最后都是对Route::setRule的封装,所以主要分析一下setRule
首先介绍一下Route的$rules的结构
thinkphp5 源码分析之二 路由解析_第6张图片

rule 为路由表达式
route为匹配路由路径
var 为指定参数   其中key为参数名  value的值 有1 或2  其中1 是必须添加 2为选填
option 为的值路由参数中提及的值(不明白请查阅文档)
pattern 为次路径下的参数限制

另外请注意,如果在注册路由时,指定的方式传类型
thinkphp5 源码分析之二 路由解析_第7张图片

protected static function setRule($rule, $route, $type \= '\*', $option \= \[\], $pattern \= \[\], $group \= '')  
{  ~~~~
  if (is\_array($rule)) {  // 是否是批量注册
  $name \= $rule\[0\];  
  $rule \= $rule\[1\];  
  } elseif (is\_string($route)) {  
  $name \= $route;  
  }  
  if (!isset($option\['complete\_match'\])) {   // 注册规则中是否有完全匹配
  if (Config::get('route\_complete\_match')) {  //配置文件中是否有完全匹配
  $option\['complete\_match'\] = true;   
  } elseif ('$' \== substr($rule, \-1, 1)) {  // 注册路由表达式中是否包含结束副
  // 是否完整匹配  
  $option\['complete\_match'\] = true;  
  }  
 } elseif (empty($option\['complete\_match'\]) && '$' \== substr($rule, \-1, 1)) {  
  // 是否完整匹配  
  $option\['complete\_match'\] = true;  
  }  
  if ('$' \== substr($rule, \-1, 1)) {  //去掉表达式中的结束符
  $rule \= substr($rule, 0, \-1);  
  }  
  if ('/' != $rule || $group) {  
  $rule \= trim($rule, '/');  
  }  
  $vars \= self::parseVar($rule);  // 提取表达式中的参数设定
 if (isset($name)) {  
  $key \= $group ? $group . ($rule ? '/' . $rule : '') : $rule;  
  $suffix \= isset($option\['ext'\]) ? $option\['ext'\] : null;  
 self::name($name, \[$key, $vars, self::$domain, $suffix\]);  
 /*注册$rules的name成员, 
 key 为对应的映射地址
 0 ==》 路由表达式
 1 ==》 参数列表
 2 ==》 域名
 4 ==》 后缀
 同时一个映射地址可以存储多个
 */
  }  
  if (isset($option\['modular'\])) {  
  $route \= $option\['modular'\] . '/' . $route;  
  }  
  if ($group) {  
  //是否设置分组
  if ('\*' != $type) {  
  //记录是哪种方式
  $option\['method'\] = $type;  
  }  
  //是否设置包含域名
  if (self::$domain) {  
  self::$rules\['domain'\]\[self::$domain\]\['\*'\]\[$group\]\['rule'\]\[\] = \['rule' \=> $rule, 'route' \=> $route, 'var' \=> $vars, 'option' \=> $option, 'pattern' \=> $pattern\];  
  } else {  
  self::$rules\['\*'\]\[$group\]\['rule'\]\[\] = \['rule' \=> $rule, 'route' \=> $route, 'var' \=> $vars, 'option' \=> $option, 'pattern' \=> $pattern\];  
  }  
 } else {  
  if ('\*' != $type && isset(self::$rules\['\*'\]\[$rule\])) {  
  unset(self::$rules\['\*'\]\[$rule\]);  
  }  
  if (self::$domain) {  
  self::$rules\['domain'\]\[self::$domain\]\[$type\]\[$rule\] = \['rule' \=> $rule, 'route' \=> $route, 'var' \=> $vars, 'option' \=> $option, 'pattern' \=> $pattern\];  
  } else {  
  self::$rules\[$type\]\[$rule\] = \['rule' \=> $rule, 'route' \=> $route, 'var' \=> $vars, 'option' \=> $option, 'pattern' \=> $pattern\];  
  //注册对应值
  }  
  if ('\*' \== $type) {  
  // 注册路由快捷方式  
  foreach (\['get', 'post', 'put', 'delete', 'patch', 'head', 'options'\] as $method) {  
  if (self::$domain && !isset(self::$rules\['domain'\]\[self::$domain\]\[$method\]\[$rule\])) {  
  self::$rules\['domain'\]\[self::$domain\]\[$method\]\[$rule\] = true;  
  } elseif (!self::$domain && !isset(self::$rules\[$method\]\[$rule\])) {  
  self::$rules\[$method\]\[$rule\] = true;  
  }  
 } } }}

到这里为止,我们通过两种方式进行了路由到注册
1 引用的Route.php 中通过使用Route::rule,Route::get等方法注册的
3 通过Route::import导入配置文件中的批量配置

路由解析

thinkphp5 源码分析之二 路由解析_第8张图片
最后在解析完成后 Route::parseRule 会返回一个result数组,为路由的调用提供依据。

2 检测路由别名
别名的设置如下
thinkphp5 源码分析之二 路由解析_第9张图片
1 检测是否为变量
2 检测是否为可选参数,如果是,去掉[]并将代表是否为可选参数的变量置为响应的值
3 执行为参数的逻辑
4 当不为参数时,检测当前url是否和规则相等

你可能感兴趣的:(php)