今天啃了路由分析这块,感觉这块还是挺复杂的;有些地方还不清楚,所以我总结一下我的理解。路由分析过程我们在使用路由分析的时候,参与路由分析的部分很多,远不止tp框架。如下图所示,我们可以看出tp框架只是manager从客户端到服务端处理响应的四个阶段中的一部分。路由url的意思是作为一个输入数据,经过路由分析,匹配到应用业务控制器(也可能是闭包函数和自定义类)路由相关参数~~~~path_infostringflag,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'=>[],domainnameDeploymentonandoff,根域名'url_domain_deploy'=>false,'url_domain_root'=>'',controller自动转换onandoff,operationautomaticconversiononandoff'url_controller_convert'=>true,'url_action_convert'=>true,//依次解析变量'url_param_type'=>1,//路由配置文件,可以配置多个'route_config_file'=>['route'],路由注册这里只是举两个栗子,想了解更多详情请参考thinkphp5.0官方手册。毕竟我们这里主要是分析源码。我将通过将我们配置文件中配置的路由规则注册到thinkRoute.php的私有静态变量$rules中来分析tp5的路由。本质上是一个测试路由,就是根据规则对$rules中的信息进行校验,所以为了便于理解,我将描述分为两部分,一是路由注册,二是路由解析;下面将根据这两部分进行分析。路由注册的整个过程如下图所示。入口app::run==>app::routeCheck===>ro??ute::import会在routeCheck中检查路由缓存是否开启,会去RUNTIME_PATH中查找是否有缓存的路由文件。如果路由文件没有导入文本,本例为route.php导入时,会执行红色标记的部分,返回的数组会执行Route::import方法,在注册的过程中route,除了组路由(我们单独分析),最后就是对Route::setRule的封装,所以我们主要分析setRule。首先介绍一下Route的$rules的结构。从get到options的位置是相似的。整个注册类似于规则作为路由表达式。公式route为匹配的路由路径,var为指定参数,key为参数名。value的值是1或者2,其中1是路由参数中提到的值(不明白的可以参考文档)pattern另外需要注意的是在注册路由的时候,会有一个优化(我的理解)路由会直接对应一个true,它对应的参数是*in$rulesStoreprotectedstaticfunctionsetRule($rule,$route,$type\='\*',$option\=\[\],$pattern\=\[\],$group\=''){~~~~if(is\_array($rule)){//是否批量注册$name\=$规则\[0\];$规则\=$规则\[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\_匹配'\]=真;}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?$组。($rule?'/'.$rule:''):$rule;$suffix\=isset($option\['ext'\])?$选项\['分机'\]:空;self::name($name,\[$key,$vars,self::$domain,$suffix\]);/*注册$rules的name成员,key是对应的映射地址0=="路由表达式1=="参数列表2=="域名4=="后缀,一个映射地址可以存放多个*/}如果(isset($option\['modular'\])){$route\=$option\['modular'\].'/'。$路线;}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'\=>$模式\];}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,'选项'\=>$选项,'模式'\=>$模式\];//注册对应值}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\]=真;}}}}}至此我们已经通过两种方式路由到注册1引用的Route.php是通过Route::rule、Route::get等方式注册的。3、通过Route导入配置文件中的批量配置::进口。路由分析路由检测主要集中在check方法上。主要过程是路由的静态检测规则检测有以下6个部分1检查路由缓存如果开启route_check_cache,在第一次缓存后,匹配成功的路由参数会被存入缓存,直接调用Route::parseRule进行解析。其实check的最后已经检查了5项最后第六步也会调用parserule进行路由转换。这里我们简单分析下parserule的要点(1)闭包注册,判断是否为闭包类。如果是结果,则返回一个闭包对象(2)如果路由是到重定向地址。tp5路由规则的第一个字符是/或者包含http://,就是重定向地址。如果是,则返回包含当前路由地址的结果。如果路由中没有设置status参数,则默认为301(3)routeto方法tp5的路由的格式是路由地址必须以根命名空间开头,所以开头必须是'\'.这里,将$route中的@替换掉,并返回提取@后的方法,最终返回结果(4)路由到controller当操作的第一个字符为@时,定义到controller方法,这里除了解析字符串返回$result对象外,还会调用Request->Action执行对应的方法(5)路由到公共模块/控制器/操作。最后,解析完成后,Route::parseRule会返回一个结果数组,这是路由调用提供的依据2.检测路由别名别名的设置如下。可以看到,如果别名对应的不是字符串地址,而是参数数组,会依次检查参数是否匹配,然后进行参数有效性检查;检测alias对应的地址,匹配其到类的路由,到控制器的路由,到模块/控制器的路由,最后匹配成功返回结果数组,匹配失败返回false,执行步骤3的其余部分检测域名。这里部署域名注册和域名检查也介绍一下域名注册:可以绑定的域名有3种有点鸡肋1.执行的时机其实是在执行注册的时候调用的。我不明白这样的调用是什么意思。2.另外,只执行了调用,没有注册闭包的参数。闭包的意思只是注册各自的域名,但是由于闭包注册是在配置文件中定义的,也就是说无论我访问哪个子域名,我还是要加载所有的闭包注册。由于这些原因,它感觉很鸡肋。动态注册规则最终会执行参数规则,并在域名中注册一份副本。结构如下图所示。域名检测对域名进行分析,得到当前路由规则中对应的值。如果对应的规则中包含'['bind']'则说明不是动态注册规则。解析后,将路由规则注册到$bind私有成员变量中。如果不包含,则说明是动态注册规则,则替换当前规则4.检测URL绑定这是对上一步中的域名绑定进行处理5.静态路由规则检测静态路由是指访问链接与注册链接一致6.路由规则检测路由规则检测的最后一部分是调用Route::parseRule,在1中已经分析过,这里不再赘述。这里我们只分析在Route::checkRoute层面做了什么。递归调用自身,传入分组参数,也就是我们注册时填写的路由分组。这里统一填写分组名称,进行路由检测,进行前置参数检查。最后在C:wamp64wwwthinkphplibrarythinkRoute::match中执行路由参数,检测当前url是否符合路由$m2为当前路由规则$m1为当前url从注册中可以看出路由规则和我们现在的访问url应该是一一对应的,除了参数。1代码中检查是否为变量2检查是否为可选参数,如果是则去掉[]并将代表是否为可选参数的变量设置为响应的值3将逻辑作为参数执行4不是参数时,检查当前url是否等于rule。普通解析(路由规则不匹配,或者没有开启路由)。在App::routeCheck中,如果没有开启路由,或者没有匹配到路由规则,只会直接进行参数解析,这里不管解析结果如何,返回的结果都是'module'类型,即路由rule//module/controller/operation解析是通过Rout::parseUrl来解析的,而这个解析其实本质上做了一件事:解析url的参数,并将参数绑定到当前的Request2填写三个参数modulecontrollermethod根据配置文件3返回和route一样的结果,只是type是module具体功能如下,检查是否有绑定的module,如果有,填入url,使用Rout::parseUrlPath()解析当前url,在解析函数中,参数为数据和路由分离,返回$path数组和$var参数数组。其实这里只是简单弹出了$path的第二个参数。之所以写这么多,主要是为了实现tp5的多层控制器。结构体,即控制器类,可以放在任意嵌套层次。for循环遍历当前url的路径。找到则弹出,并复制controller的popup方法,封装路由,返回
