thinkphp5 源碼分析之二 路由解析

今天啃關於路由解析的部分,感受這塊仍是挺複雜的;有的點仍是沒看透,把看明白的總結出來。php

路由解析的流程

咱們在使用路由解析的時候,不少部分參與了路由解析,遠不止tp框架以下圖
image.png
能夠看出從客戶端發起到服務器處理響應,經理的4個階段,tp框架只是其中一部分。html

路由的意義

url做爲一種輸入的數據,過路由解析,
匹配到應用業務控制器(也有多是閉包函數和自定義的類)thinkphp

路由相關的參數~~~~

image.png
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官方手冊畢竟這裏咱們是以分析源碼爲主。
image.png服務器

源碼解析

我將tp5的路由解析是將咱們配置文件中配置的路由規則註冊進thinkRoute.php的私有靜態變量$rules,本質上來講檢驗路由就是按規則將$rules中的信息進行校驗, 因此爲了便於理解,我將講述分爲兩部分, 一部分是路由註冊, 一部分是路由解析;下面將會根據這兩部分進行分析。閉包

路由註冊

整個過程以下圖
image.png
入口
app::run==>app::routeCheck===>route::import
在routeCheck中會檢查是否開啓路由緩存,同時會去RUNTIME_PATH下查找是否有緩存的路由文件,若是沒有引入文入路由文件,在本例中便是route .php 當引入app

image.png

會執行其中標紅的部分,返回的數組,會執行Route::import 方法,而在註冊路由的過程當中除了分組路由之外(咱們另外分析),最後都是對Route::setRule的封裝,因此主要分析一下setRule
首先介紹一下Route的$rules的結構
image.png
其中get到options位置都是類似的,一個整的註冊相似與
image.png框架

rule 爲路由表達式
route爲匹配路由路徑
var 爲指定參數   其中key爲參數名  value的值 有1 或2  其中1 是必須添加 2爲選填
option 爲的值路由參數中說起的值(不明白請查閱文檔)
pattern 爲次路徑下的參數限制

另外請注意,若是在註冊路由時,指定的方式傳類型
image.png
會有一個優化(在我理解)
image.png
會將路由直接對應一個true,而其對應的參數在$rules中的*中存儲
image.pngdom

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導入配置文件中的批量配置

路由解析

image.png
路由檢測主要集中在check方法內 主要過程是
image.png
靜態檢測
image.png
路由規則檢測
image.png
也就是一下6部分
1 檢查路由緩存
若開啓 route_check_cache 時,則在第一次緩存後將匹配成功的路由參數
存儲在緩存中
image.png
直接調用Route::parseRule進行解析
其實在check的最後檢查過5項後最後第六步也會調用parserule進行路由轉換,這裏就一併分析了
簡單分析下parserule關鍵的地方
image.png
(1)閉包註冊
判斷是否爲閉包類 若是是result返回閉包對象
(2)若是路由是到重定向地址
tp5路由規則中 首字符爲/ 或包含http://既爲重定向地址
若是是則返回result 包含當前的路由地址,若是路由沒有設置status參數則默認爲301
(3)路由到方法
tp5 的路由到方法的格式爲
image.png
路由地址必須從跟命名空間開始,因此開頭必須爲'\'
這裏處理將$route 中的@替換回來
提取@後的method
最後返回result
(4)路由到控制器操做
image.png
當首字符爲@的時候則定義到控制器方法,
這裏除了解析字符串返回$result對象意外
會調用Request->Action執行對應的方法
(5)路由到普通的 既模塊/控制器/操做
image.png
最後在解析完成後 Route::parseRule 會返回一個result數組,爲路由的調用提供依據。

2 檢測路由別名
別名的設置以下
image.png
咱們能夠看到 若是別名對應存儲的不是一個字符串地址,而是參數數組,則會依次檢查參數的是否符合
image.png
後面依次是參數有效性檢查 ; 檢測別名對應地址,匹配其路由到類,路由到控制器,路由到模塊/控制器,的需求
image.png
最後若是匹配成功,返回result數組,若是匹配失敗則返回false,執行其他步驟
3 檢測域名部署
這裏也將域名的註冊 和域名的檢查同時介紹
域名註冊:
域名能夠綁定的類型有三種
image.png
下圖爲註冊函數
image.png
能夠看見domain函數會直接進行註冊,將路由地址,路由參數,參數規則
image.png
這裏我以爲閉包函數的規則有點雞肋
1 執行時機
image.png
竟然是在執行註冊的時候就進行調用,我不明白這樣的調用有什麼意義
2 另外只執行了調用卻沒有對閉包的任何參數進行註冊。
閉包存在的意義就只有分別對各自域名進行註冊
image.png
但是因爲這個閉包註冊是定義在配置文件中的,那樣就是說不論我是訪問哪個子域名,我仍是要加載全部的閉包註冊。因爲這些緣由因此感受仍是比較雞肋的。
而動態註冊規則
最終會執行
image.png
將參數的規則除了在name中
另外註冊一份在domain中,結構以下圖
image.png
域名檢測
對域名進行解析
image.png
得到當前路由規則中對應的值
若是對應的規則包含'['bind']' 說明不是動態註冊規則,則在解析後,將路由規則註冊進$bind私有成員變量
image.png
若是不包含說明是動態註冊規則
image.png
則替換目前的規則
image.png
4 檢測URL綁定
image.png
這裏就是處理上一步中域名綁定的規則,將其處理爲result返回跳轉
5 靜態路由規則檢測
image.png
靜態路由是指,訪問連接和註冊連接一致
image.png
6 路由規則檢測
路由規則檢測最後部分是調用的是Route::parseRule,這一部分在1中已經分析過,在這裏就不重複了,這裏只分析Route::checkRoute層面上作了什麼
1 遍歷當前訪問方式的rules
image.png
當前訪問方式的規則數組rules,遍歷當前訪問方式的路由規則
image.png
若是是分組路由則遞歸調用自身,並將分組參數傳入
image.png
也就是說咱們註冊時填充的路由分組,到這裏會統一將分組名稱填寫徹底後進行路由檢測
image.png
執行前置的參數檢查,最後在C:wamp64wwwthinkphplibrarythinkRoute::match中執行路由的參數,和當前url 是否符合路由的檢測
image.png
檢測$m2 爲當前路由規則
$m1 爲當前url
image.png
從註冊中能夠看出路由規則 和咱們當前的訪問url 除開參數意外,應該是一一對應的,代碼中爲
image.png1 檢測是否爲變量2 檢測是否爲可選參數,若是是,去掉[]並將表明是否爲可選參數的變量置爲響應的值3 執行爲參數的邏輯4 當不爲參數時,檢測當前url是否和規則相等

相關文章
相關標籤/搜索