首頁 > php框架 > ThinkPHP > 主體

ThinkPHP路由位址是怎麼進行控制器實例化的

咔咔
發布: 2020-12-04 13:32:40
原創
147 人瀏覽過

一、執行控制器中的方法

#本文的請求位址為配置的網域名稱。

ThinkPHP路由位址是怎麼進行控制器實例化的
請求位址

透過上文可以知道$instance的值就是app\index\controller\Index的實例。

這塊也是存在中間件的概念,依然如此中間件會在後文中單獨提到,這裡不做解釋。

在這裡$this->app['middleware']->controller這段程式碼的使用,還能記得是使用的ArrayAccess還是直接為__get嗎?

這裡是在使用存取數組的形式存取對象,所以使用的是ArrayAccess的形式,這兩個概念一定要區分清楚。

ThinkPHP路由位址是怎麼進行控制器實例化的
透過反射執行控制器的方法

接下來就會執行取得方法名,至於這個方法名稱怎麼取得的是在本類別的init方法執行的,這裡只需要知道回傳的是index即可。

在這裡要注意的就是這行程式碼$this->rule->getConfig('action_suffix'),這裡取得的是運算方法後綴。

ThinkPHP路由位址是怎麼進行控制器實例化的
操作方法字尾

假如現在給這個運算元後綴設定一個值會變成什麼樣子呢!

給新增一個kaka的值,進行訪問一下看看會是什麼結果。

ThinkPHP路由位址是怎麼進行控制器實例化的
加入了kaka進行測試

這個時候進行存取會提示indexkaka的這個方法不存在,是不是清晰可見了,表示這個參數是在為所有的方法名追加一個kaka。

ThinkPHP路由位址是怎麼進行控制器實例化的
存取結果

對取得目前運算元的程式碼擴充完成之後,緊接著是if (is_callable([$instance, $ action])) {,在這裡可以看見我們的老朋友is_callable

對於這裡的is_callable兩個參數透過上文都知道是什麼了,第一個參數為app\index\controller\Index的實例,第二個參數為index執行操作方法。

那麼is_callable的作用就是偵測在app\index\controller\Index類別中的index方法名稱是否可以執行。

很明顯這裡會回傳一個true,因為在index類別裡邊存在index方法的。

這裡在做測試之前一定要把剛剛在app的設定檔中設定的方法名稱後綴那個給取消掉。

透過這個is_callable判斷會有三種情況,接下來喀喀就會從三個面向給大家解析。

第一種情況:類別裡邊存在可執行的方法

  • #首先傳回一個ReflectionMethod 類別
  • 取得方法名稱index
  • 未設定方法名稱後綴回傳空
  • 設定目前的操作名稱
  • #在這個案例中沒有設定參數,所以最終的$vars就是空數組。

為了測試這一段有參數的程式碼,我們需要對路由位址做一點改變。

ThinkPHP路由位址是怎麼進行控制器實例化的
測試部分程式碼

在之前沒有使用路由,而是直接使用的預設位址,接下來將使用這個路由位址

ThinkPHP路由位址是怎麼進行控制器實例化的
使用新的路由位址進行測試

使用這個路由位址進行一下資料的列印,可以看到就是我們設定的路由參數。

ThinkPHP路由位址是怎麼進行控制器實例化的
資料列印

這段取得請求變數的方法會進入到$this->request->param();這行程式碼

框架是如何取得參數的

存取位址:http://www.source.com/index.php/hello/hello

在上文知道是透過$this->request->param()來取得參數的,那麼在框架是如何取得參數的呢!

根據流程程式碼會執行到下圖,根據取得的請求方式來使用對應的方式來取得參數,在這裡需要明確的是我們使用的是get請求。

所以程式碼會執行到$this->param,目前請求參數和URL位址中的參數合併這裡,在這裡註意咔咔圈出來的地方。

由於咔咔是使用路由方式進行的請求所以,在這裡框架專門為路由封裝了一個獲取請求參數。

ThinkPHP路由位址是怎麼進行控制器實例化的
取得目前請求的參數

來到這個route方法,看到註解就明白是用來取得路由參數的,但還是需要在進入一層到input。

ThinkPHP路由位址是怎麼進行控制器實例化的
取得路由參數

在先前路由的那一期文章中在取得到路由參數的時候會把參數合併到request的route屬性。

ThinkPHP路由位址是怎麼進行控制器實例化的
設定路由變數

所以說$this->route就是存放的這條路由規則所有的參數,包含路由參數。

ThinkPHP路由位址是怎麼進行控制器實例化的
列印結果

這時執行流程會執行到取得變數支援過濾和預設值,在上文$this->route 穿進來的參數是false,所以說這塊會直接回傳。

获取变量 支持过滤和默认值
取得變數支援過濾和預設值

這裡回傳的結果會回傳給上文我們開始解析的地方,也就是說這個$vars就是要取得到的路由參數。

ThinkPHP路由位址是怎麼進行控制器實例化的
傳回的路由參數結果

第二種情況:類別裡邊不存在可執行的方法

#當第一種判斷執行is_callable判斷類別裡邊的方法不可執行時,就會執行到第二種情況。

ThinkPHP路由位址是怎麼進行控制器實例化的
第二種執行情況

先來請求的一個沒有設定的路由位址,看會回傳什麼。

ThinkPHP路由位址是怎麼進行控制器實例化的
錯誤回傳

根據程式碼給的提示,我們來到index控制器建立一個_empty方法,然後在來請求一次,看看會發生什麼事。

ThinkPHP路由位址是怎麼進行控制器實例化的
在控制器設定_empty方法

根據列印結果就可以看出來當存取的方法不存在時就會去執行_empty這個方法。

ThinkPHP路由位址是怎麼進行控制器實例化的
列印結果

那麼這個方法是怎麼執行的呢!這種執行方式就是利用反射機制來實現的,關於反射咔咔之前專門出了一篇文章來講解的,但是大家還是需要對著文檔進行閱讀查看。

第三種情況:類別裡邊不存在可執行的方法也不存在_empty方法

這種情況就比較簡單了,就是直接回傳錯誤訊息,關於這裡異常處理咔咔也會在後文說到。

ThinkPHP路由位址是怎麼進行控制器實例化的
第三種情況

三種情況執行完

## 三種情況分析完了,最後都會去執行統計的方法。

呼叫反射執行類別的方法 支援參數綁定,也就說這裡的閉包執行流程到這裡就執行完了。

關於後邊的自動請求,在第五節中詳細說明。

ThinkPHP路由位址是怎麼進行控制器實例化的
統計執行

二、路由位址是怎麼進行控制器實例化的

#在上一節我們對路由進行了三四期的講解,最後講解的位置就路由調度,那麼設定的路由是如何執行呢!

接下來使用這個路由作為案例

ThinkPHP路由位址是怎麼進行控制器實例化的
ThinkPHP路由位址是怎麼進行控制器實例化的

#還記得在開始進行路由偵測時的回傳值是什麼嗎?請看下圖

ThinkPHP路由位址是怎麼進行控制器實例化的
路由偵測
ThinkPHP路由位址是怎麼進行控制器實例化的
#列印結果

當時沒有對接下裡的程式碼進行詳解,直接說明了實例化控制器,現在要說的就是記錄當前調度資訊這行程式碼。

在這裡$this->request是使用的當存取不存在的屬性時會去執行容器類別的魔術方法,最後透過容器傳回一個實例。

所以說程式碼會執行到下圖位置,設定或取得目前請求的調度資訊

ThinkPHP路由位址是怎麼進行控制器實例化的
設定或取得目前請求的調度資訊

透過在控制器實例化這裡進行列印會發現在這裡的傳回的值是index,這個值是在控制器進行設定的,接下來來到控制器查看一下。

ThinkPHP路由位址是怎麼進行控制器實例化的
列印資料

來到init方法對result做列印查看結果,使用的是路由位址

ThinkPHP路由位址是怎麼進行控制器實例化的# #列印資料
ThinkPHP路由位址是怎麼進行控制器實例化的使用路由位址
没有ThinkPHP路由位址是怎麼進行控制器實例化的#沒有使用路由位址

你知道到為什麼這裡的數值改變了嗎?

在上文印出來的值是下圖,為什麼這裡就是上圖的呢!

ThinkPHP路由位址是怎麼進行控制器實例化的列印結果
在路由那一節最後一步就是發起路由調度,最後呼叫了一個路由到模組/控制器/操作這個方法。

ThinkPHP路由位址是怎麼進行控制器實例化的
路由調度

這個方法dispatchModule最後也是實例化一個類,接下來需要對這個類別進行深究

ThinkPHP路由位址是怎麼進行控制器實例化的
#路由到模組/控制器/操作

根據程式碼追蹤可以看到其實就是think\route\dispatch\Module這個類別

ThinkPHP路由位址是怎麼進行控制器實例化的
類別的別名

來到Module這個類,又會發現繼承著Dispatch類別

ThinkPHP路由位址是怎麼進行控制器實例化的
類別的繼承

thinkphp/library/think/route/Dispatch.php這個類別的控制器中,會發現對 dispatch這個變數進行了設定。

ThinkPHP路由位址是怎麼進行控制器實例化的
變數賦值

這時候回頭在看路由到模組/控制器/操作這裡的方法傳入的參數是什麼,哈哈

ThinkPHP路由位址是怎麼進行控制器實例化的的参数
路由到模組/控制器/操作的參數

所以說最終的值就是剛剛列印的只是單獨的陣列形式的。

ThinkPHP路由位址是怎麼進行控制器實例化的
實例化控制器

那麼接下來的動作就跟不使用路由存取的流程一樣的,就不用在進行解析了。

直到這裡關於路由位址是怎麼進行控制器實例化的就結束了。

關於給$this->app->controller傳入的是index,回傳的是整個類別名,具體的實作過程就不去解析了,實作的方法是$this->parseModuleAndClass,可以自行進行研究哈!

三、執行autoResponse調度

在第四節只提到了執行控制器中的方法是從下圖的地方進行返回的,但是怎麼返回的沒有進行詳解。

接下裡會用一丟丟的時間來說一下是如何執行的。

ThinkPHP路由位址是怎麼進行控制器實例化的
自動請求

存取路由位址為下圖,可以看到傳回的資料就是控制器中需要傳回的資料。

ThinkPHP路由位址是怎麼進行控制器實例化的
控制器傳回的資料
ThinkPHP路由位址是怎麼進行控制器實例化的
列印data的值

列印的值是下圖地方,這裡就需要明確哈!源碼閱讀就是這樣需要一點點的進行摸索,時間長了就對其中的東西就明白了。

ThinkPHP路由位址是怎麼進行控制器實例化的
列印的位置

接下來就對$this->autoResponse($data);這個方法進行深入的解析,這個方法按照字面意思就是自動響應。

ThinkPHP路由位址是怎麼進行控制器實例化的
自動回應

在這個執行流程的第一行中$data instanceof Response,對這個不了解接下來就沒辦法閱讀了。

不會和不懂的還是需要去解決的,閱讀原始碼就這樣,一點點的攻克才能獲得勝利。

關於instanceof的使用

instanceof可以判斷某個物件是否是某個類別的實例,判斷一個物件是否實作了某個介面。

接下來喀喀爾針對這個做一個簡單的實例給大家示範一下,就明白這個是怎麼回事了。

案例一

先建立兩個類,案例如下圖。

ThinkPHP路由位址是怎麼進行控制器實例化的
示範案例

下圖就是列印結果,可以看到第一個回傳true,第二個回傳false。

判斷某個物件是否是某個類別的實例,也就是說$instance就是類別Test的實例,所以會回傳true。

ThinkPHP路由位址是怎麼進行控制器實例化的
列印結果

案例二#​​

##案例二跟案例一是不同的,建立了一個接口,然後類別實作介面的案例。

ThinkPHP路由位址是怎麼進行控制器實例化的二
示範案例二

最終傳回結果全是true,也就是說如果一個類別實作了另一個接口,那麼在判斷時都會是true。

ThinkPHP路由位址是怎麼進行控制器實例化的
列印結果

以上就是針對instanceof給予的兩個組合示範案例,對其理解就是判斷一個實例是否為某個類別的實例。

那麼就回到正文,$data instanceof Response這行程式碼絕對不會成立,因為data傳過來的就是控制器回傳的值。

所以說程式碼執行流程會執行到下圖位置,使用了is_null函數來做判斷,判斷肯定為false,所以會執行以下的程式碼。

在這塊程式碼中前兩個點就不去解析了。

第一個就是預設自動辨識回應輸出類型,這裡就是在判斷是否為ajax請求,具體實現方法等咔咔這次把框架源碼解析完之後,然後每天會抽一點時間,對框架的一些方法進行一點點的剖析。

第二處位置就是在設定檔獲取對應的配置信息,看的是執行的rule類別的方法,但是在方法中是執行的獲取配置信息的代碼。

ThinkPHP路由位址是怎麼進行控制器實例化的
程式碼第一癡執行流程執行到的位置

接下就需要對上文沒提到的第三處進行解析了,也就是程式碼$response = Response::create($data, $type);

來到類別thinkphp/library/think/Response.php的方法create 中,這個方法就是用來建立Response物件。

這裡只需要去關註一下喀喀爾出來的地方即可,在thinkphp/library/think/response這個目錄下是不存在html的。

所以程式碼會直接去實例化本類,然後進行回傳。

ThinkPHP路由位址是怎麼進行控制器實例化的
建立Response物件

來到本類別的建構子就主要做一下幾件事情。

  • 將傳回值賦給本類的data屬性
  • #設定頁面輸出類型
  • 傳回狀態碼
  • 設定app實例物件
  • 頭部資訊
ThinkPHP路由位址是怎麼進行控制器實例化的##在這裡插入圖片描述
然後程式碼會將回傳值賦值給

autoResponse這個方法的$response這個變數。

最後就是將這個

$response給回傳出去,並且回傳資訊如下圖列印結果。

ThinkPHP路由位址是怎麼進行控制器實例化的在這裡插入圖片描述
ThinkPHP路由位址是怎麼進行控制器實例化的#列印出回傳訊息
然後程式碼依然會向上層返回,回到最初的閉包函數。

在喀喀爾圈出來的地方,下一行程式碼也是關於中間件,只需要知道最終回傳結果跟上圖列印的結果一樣即可。

ThinkPHP路由位址是怎麼進行控制器實例化的
回到中間級件那一層

最終回傳結果回到thinkphp/library/think/route/Dispatch.php,咱們也就是從這裡開始的解析的。

ThinkPHP路由位址是怎麼進行控制器實例化的
在這裡插入圖片描述

將傳回的結果傳回給$data,然後在進行執行return $ this->autoResponse($data);

你沒看錯,這裡的程式碼熟悉吧!

這個時候回傳的結果就是Response的實例,所以會直接回傳$response

ThinkPHP路由位址是怎麼進行控制器實例化的
自動回應

直到這裡關於執行控制器中的方法,並且回應就都解析完了。

不輪是設定的路由規則,還是直接使用模組控制器方法的方式存取最終都會透過上文的方式進行回傳回應結果。

堅持學習、堅持寫博、堅持分享是咔咔從業以來一直所秉持的信念。希望在偌大互聯網中咔咔的文章能帶給你一絲絲幫助。我是咔咔,下期見。

以上是ThinkPHP路由位址是怎麼進行控制器實例化的的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
1
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!