ThinkPHP源碼解析控制器(thinkphp 控制器)

      網友投稿 1075 2022-05-30

      本文會對控制器的執行順序還有實現過程、源碼解析給出解析,

      ThinkPHP源碼解析之控制器

      前言

      一、實例化控制器

      二、關于ArrayAccess和直接執行魔術訪問返回實例的區別

      三、執行控制器中的方法

      四、路由地址是怎么進行控制器實例化的

      五、執行autoResponse調度

      六、如何輸出數據到終端

      七、fastcgi_finish_request方法巧用

      八、trait特性講解

      總結

      前言

      在上文中對路由進行了特別的詳解,也從應用初始化開始解析一直到路由調度返回給路由檢測這一環節。

      路由檢測獲取到的值如下圖,也就是路由調度最終返回的值。

      使用的路由規則為Route::get('hello/:name', 'index/index/:name');

      從上圖可以看出重要數據都是在dispatc中存放的,接下來就會對控制器進行詳解。

      最先說明的就是的當路由檢測完畢之后執行的實例化控制器操作。

      一、實例化控制器

      先來看一下是怎么執行到實例化控制器吧!

      毫無疑問代碼肯定是先從入口文件開始執行的,這里使用容器返回一個App的實例,然后去調用App類中的run方法。

      下來就會來到執行應用程序,在這個方法中也是在上文剛剛解析的路由。

      所以檢測路由執行完就會去執行實例化控制器。

      在路由檢測執行完之后返回的是think\route\dispatch\Module Object這個類,并且這個類賦值給了變量$dispatch

      接著看一下本方法的這塊代碼,這里使用的是中間件,在這快代碼中還是用了閉包,對閉包的概念不清晰的就需要回頭啃基礎了。

      在上圖中咔咔圈出來的一個地方就是$dispatch->run()這塊代碼,接下來就要對這塊代碼進行解析了。

      在檢測路由最終的返回值可以知道其實這個方法是在think\route\dispatch\Module這個類中。

      接著就需要對這個類中的run方法進行解析了,這個方法也就是執行路由調度。

      在這個方法中不管是獲取路由參數還是檢測路由、數據自動驗證都不會執行(是按照咔咔上文給的路由地址為案例)。

      所以根據上圖代碼就會執行到$data = $this->exec();這里。

      跟蹤這個方法會到下圖地方存在一個抽象類,這里需要知道的是抽象類。

      對抽象類做出解釋

      抽象類不能被實例化

      有抽象方法的類一定是抽象類;類必須要abstract修飾

      抽象方法不能有函數體;即abstract function fun();

      抽象類中的非抽象方法,可以被子類調用

      非抽象子類繼承抽象類,子類必須實現父類的所有抽象方法

      抽象子類繼承抽象類,無需繼承父類的抽象方法

      根據上圖的原則可以看到Dispatch這個類是抽象類。

      所以就會有倆種情況, 一種是抽象類繼承抽象類,無需繼承父類的抽象方法。

      另一種是非抽象子類繼承抽象類,子類必須實現父類的所有抽象方法。

      怎么去找誰繼承了Dispatch

      這個時候是不是有一個疑問就是怎么去找Dispatch的子類。

      在這個圖中可以看到本類Dispatch,但是還有一個dispatch這個目錄。

      根據路由檢測返回的數據可以輕而易舉的就知道是thinkphp/library/think/route/dispatch/Module.php這個類。

      來到thinkphp/library/think/route/dispatch/Module.php查看exec方法。

      那么接下來的任務就是對這個方法進行深入的解讀了。

      先看第一行代碼$this->app['hook']->listen('module_init');,在這里使用了容器ArrayAccess用數組的形式訪問對象,然后執行的魔術方法__get,當訪問不存在的屬性時會去執行make方法。

      使用編輯器追蹤這個app會到thinkphp/library/think/route/Dispatch.php這個類里邊,在這個類的構造函數中可以看到對于app這個屬性是賦值了一個App實例。

      接著來到App類可以看到繼承的是Container類。

      在容器這塊已經不止一次的說過這塊的知識點了,訪問不存在的屬性回去執行容器的__get魔術方法。

      所以說這塊的參數會傳入hook,并且會返回hook的實例,關于這個實例是怎么返回的在容器那一節中說的很是詳細,可以去看一下哈!

      接下來就會去執行hook的listen方法,監聽標簽的行為。

      此時可以來到應用行為擴展定義文件,可以看到這個參數為模塊初始化,但是因為這個值是空的。

      所以在上圖不會去執行,那么就把應用初始化的值給放到這個參數里邊進行簡單的測試。

      這個類就是執行的鉤子,對門面類的優化操作。

      那么代碼就會執行到$results[$key] = $this->execTag($name, $tag, $params);這里來。

      參數說明

      $name = string(22) “behavior\LoadBehavior”

      $tag = module_init

      接著通過正則對傳過來的參數進行處理,最終返回moduleInit

      然后通過$obj = Container::get($class);返回behavior\LoadBehavior的實例

      最終通過is_callable這個函數進行驗證,檢測類里邊的方法是否可以被調用,方法數組格式,這個方法后期咔咔單獨寫一篇文章作為對象來解析,這里只需要知道會返回false即可。

      然后會把本類的$portal這個值賦值給$method,這個值就是run。

      最后通過$result = $this->app->invoke($call, [$params]);這行代碼,這行代碼的底部執行就是通過反射機制實現的。

      最后這段代碼會返回NULL。

      實例化控制器

      接下來就是進行實例化控制器,調用的方法是$this->app->controller()

      這里需要注意的是list這個函數,這個函數的后邊會返回一個數組,然后list中的倆個變量會分別為索引0和1。

      判斷也會去執行第一個,同樣會執行到容器類的make方法,這個方法會直接返回app\index\controller\Index這個類的實例。

      二、關于ArrayAccess和直接執行魔術訪問返回實例的區別

      有一部分小伙伴都已經學會了ArrayAccess和魔術方法__get的使用了。

      估計也有一部分在這倆個地方處于模糊地段,咔咔將這倆個放在一起在解析一次。

      ThinkPHP源碼解析之控制器(thinkphp 控制器)

      先聊ArrayAccess的使用

      這個案例在之前也給大家演示過,主要就是實現ArrayAccess的這個類。

      然后在來到控制器進行使用,先進行實例化,之前實現的案例如下。

      但是這次需要實現的案例并不是下圖所實現的。

      接下來使用下圖的方式進行訪問,直接使用數組訪問對象屬性。

      在上圖中可以看到設置了一個屬性title為kaka,在這個案例中直接用數組形式直接獲取。

      看到返回結果為kaka,也就是說直接使用數組形式訪問對象的屬性。

      框架實戰案例

      在上一期文章中解析的路由中存在以下代碼,接下來進行簡單的解析一下。

      先來看一下這個app的值打印出來就是think\App Object對象。

      當think\App Object這個對象去訪問request時,因為app屬性就沒有這個request,又因為app類是繼承著container類,所以會去容器類執行下圖方法。

      然后就會去執行__get方法,執行make方法返回對應的實例。

      此時你要是還有疑問就是,怎么就咔咔說會執行就會執行呢!

      接下來咔咔帶著大家做一個簡單的測試就知道了。

      在這個位置中隨機打印一個數值。

      然后來到容器類的ArrayAccess的offsetGet方法中打印一下傳過來的值。

      看一下打印結果,就很明確了。

      關于ArrayAccess的使用就到這里就結束了,這也是在之前的基礎上詳細的進行了一次說明,接下來對容器中的__get方法進行詳解,看在什么情況會執行__get方法。

      __get方法使用詳解

      這個案例請看下圖中的這個$this->hook。

      同樣的道理先來調試一下這個$this是什么值。

      打印這個值都沒什么必要,因為就是在本類中。

      在類中屬性的訪問應該都會,就是直接使用$this-> 即可。

      所以說當系統訪問$this->hook這個的時候,由于App類是不存在hook這個屬性的,所以就會去執行容器類的魔術方法。

      然后在去執行make方法,創建類的實例。

      三、執行控制器中的方法

      本文的請求地址為配置的域名。

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

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

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

      這里是在使用訪問數組的形式訪問對象,所以使用的是ArrayAccess的形式,這倆種概念一定要區分清楚。

      接下來就會執行獲取方法名,至于這個方法名怎么獲取的是在本類的init方法執行的,這里只需要知道返回的是index即可。

      在這里需要注意的就是這行代碼$this->rule->getConfig('action_suffix'),這里獲取的是操作方法后綴。

      假如現在給這個操作方法后綴設置一個值會變成什么樣子呢!

      給添加一個kaka的值,進行訪問一下看會是什么結果。

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

      對獲取當前操作名的代碼進行擴展完成之后,緊接著就是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就是一個空數組。

      為了測試帶有參數的這一段代碼,我們需要對路由地址進行一點改動。

      在之前沒有使用路由,而是直接使用的默認地址,接下來將使用這個路由地址

      使用這個路由地址進行一下數據的打印,可以看到就是我們設置的路由參數。

      這段獲取請求變量的方法會進入到$this->request->param();這行代碼

      框架是如何獲取參數的

      訪問地址:http://www.source.com/index.php/hello/hello

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

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

      所以代碼會執行到$this->param,當前請求參數和URL地址中的參數合并這里,在這里注意咔咔圈出來的地方。

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

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

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

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

      這時執行流程會執行到獲取變量 支持過濾和默認值,在上文中$this->route穿進來的參數是false,所以說這塊會直接返回。

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

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

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

      先來請求的一個沒有設置的路由地址,看會返回什么。

      根據代碼給的提示,我們來到index控制器建立一個_empty方法,然后在來請求一次,看一下會發生什么。

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

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

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

      這種情況就比較簡單了,就是直接返回錯誤信息,關于這里異常處理咔咔也會在后文說到。

      三種情況執行完

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

      調用反射執行類的方法 支持參數綁定,也就說這里的閉包執行流程到這里就執行完了。

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

      四、路由地址是怎么進行控制器實例化的

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

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

      還記得在開始進行路由檢測時的返回值是什么嗎?請看下圖

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

      在這里$this->request是使用的當訪問不存在的屬性時會去執行容器類的魔術方法,最后通過容器返回一個實例。

      所以說代碼會執行到下圖位置,設置或者獲取當前請求的調度信息

      通過在控制器實例化這里進行打印會發現在這里的返回的值是index,這個值是在控制器進行設置的,接下來來到控制器進行查看一下。

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

      你知道到為什么這里的值發生改變了嗎?

      在上文打印出來的值為下圖,為什么在這里就是上圖的呢!

      在路由那一節中最后一步就是發起路由調度,最后調用了一個路由到模塊/控制器/操作這個方法。

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

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

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

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

      這個時候回頭在看一下路由到模塊/控制器/操作這里的方法傳入的參數是什么,哈哈

      所以說最終的值就是剛剛打印的只是單獨的數組形式的。

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

      直到這里關于路由地址是怎么進行控制器實例化的就結束了。

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

      五、執行autoResponse調度

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

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

      訪問路由地址為下圖,可以看到返回的數據就是控制器中需要返回的數據。

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

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

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

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

      關于instanceof的使用

      instanceof可以判斷某個對象是否是某個類的實例,判斷一個對象是否實現了某個接口。

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

      案例一

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

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

      判斷某個對象是否是某個類的實例,也就是說$instance就是類Test的實例,所以會返回true。

      案例二

      案例二跟案例一是不同的,建立了一個接口,然后類實現接口的案例。

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

      以上就是針對instanceof給出的倆種演示案例,對其理解就是判斷一個實例是否為某個類的實例。

      那么就在回到正文,$data instanceof Response這行代碼肯定不會成立,因為data傳過來的就是控制器返回的值。

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

      在這塊代碼中前倆個點就不去解析了。

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

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

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

      來到類thinkphp/library/think/Response.php的方法create中,這個方法就是用來創建Response對象。

      這里只需要去關注一下咔咔圈出來的地方即可,在thinkphp/library/think/response這個目錄下是不存在html的。

      所以代碼會直接去實例化本類,然后進行返回。

      來到本類的構造函數就主要做一下幾件事情。

      將返回值賦給本類的data屬性

      設置頁面輸出類型

      返回狀態碼

      設置app實例對象

      頭部信息

      然后代碼會將返回值賦值給autoResponse這個方法的$response這個變量。

      最后就是將這個$response給返回出去,并且返回信息如下圖打印結果。

      然后代碼依然會向上層返回,回到最初的閉包函數。

      在咔咔圈出來的地方,下一行代碼也是關于中間件,只需要知道最終返回結果跟上圖打印的結果一樣即可。

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

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

      你沒看錯,這里的代碼熟悉吧!

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

      直到這里關于執行控制器中的方法,并且響應就都解析完了。

      不輪是設置的路由規則,還是直接使用模塊控制器方法的方式訪問最終都會通過上文的方式進行返回響應結果。

      六、如何輸出數據到終端

      當執行完控制器中的方法響應數據給App類的run方法,直到這里就已經執行完了。

      是不是有點懵這里的數據最終會返回哪里呢!

      之前寫過的框架執行流程、路由、控制器實例化都是從這里開始進入的。

      所以當run方法執行完成之后,就會把對應的結果給返回到這里。

      這一部分的代碼Container::get('app')應該都知道了是返回一個App類的實例。

      然后通過App類去執行run方法,才會有之前講過的一切。

      下圖是咔咔從半中腰做的一個思維導圖,前面的沒有,后邊的所有知識點都會寫在這個思維導圖里。

      執行完run方法就會去執行Container::get('app')->run()->send()send這個方法,有多少人會認為在App類里邊執行send方法。

      其實不是的,回想一下之前執行控制器方法然后返回的響應結果是什么?

      如果你不是很粗略的看都會記得是Response的一個對象實例。

      所以說send方法會去response類里邊去執行。

      先不看其它的,先看這行代碼$this->app['hook'],現在知道是執行的那里嗎?

      這種形式就是通過訪問數組形式去訪問對象的屬性,也就是之前解析的ArrayAccess這個類。當訪問的屬性不存在時會去執行offsetGet,然后執行魔術方法__get,最終通過make方法返回實例,這一切的操作都是在容器中。

      對這行代碼具體是監聽的什么就不去做解析了。

      接著需要看處理輸出數據的這行代碼$data = $this->getContent();

      這個方法做的事情就是將傳過來的數據賦值給本類的content屬性。

      其實在獲取輸出數據這個方法中,請看咔咔圈出來的第一個地方感覺是很沒有必要。

      可以看到根本對數據就沒有任何的處理,只是簡單的返回了,所以說框架有好的地方也有不好的地方,只有你去閱讀了才會知道,否則你會對你經常使用的工具一無所知。

      在接著就是Trace調試注入,就是通過配置文件配置的,通過調用debug類實現的,這里就不詳解了。

      然后就是緩存判斷,緩存會在后文中單獨拎出來講,所以也是過。

      在接下來就對響應頭的設置了,檢測 HTTP 頭是否已經發送,這塊的東西就很重要了,也是平時接觸不多的知識點了。

      headers_sent() : 檢測 HTTP 頭是否已經發送

      http_response_code() :獲取/設置響應的 HTTP 狀態碼

      header : 函數向客戶端發送原始的 HTTP 報頭。

      最后一步,來了來了,它來了,它帶著echo來了,執行了一個方法$this->sendData($data);

      給人一種媳婦熬成娘的感覺,終于來到的終點站,一個echo輸出了咔咔幾十天的心酸啊!

      為了到達這個echo咔咔是經歷九九八十一難啊!戰斗還未停止,同志仍需努力啊!

      那么到這里關于框架執行然后到應用初始化,在到路由檢測、控制器的實例化、然后返回response實例,在通過入口文件執行send方法。

      最后將數據輸出到終端,也就是一個echo的事情。

      雖然這里的戰斗結束了,但是在下面還有一個非常重要的知識點,咔咔將重新提一節來進行說明。

      七、fastcgi_finish_request方法巧用

      在上一節中通過Container::get('app')->run()->send();在response類中執行了send方法,輸出了數據。

      但是在輸出數據之后還執行了一個方法fastcgi_finish_request();,給的注釋是提高頁面響應,接下來好好來扒一扒其中的奧秘。

      在PHP官網中看到這樣一段話

      The script will still occupy a FPM process after fastcgi_finish_request(). So using it excessively for long running tasks may occupy all your FPM threads up to pm.max_children. This will lead to gateway errors on the webserver.

      在fastcgi_finish_request()之后,腳本仍將占用FPM進程。 因此,對于長時間運行的任務過度使用它可能會占用您的所有FPM線程,直到pm.max_children。 這將導致Web服務器上的網關錯誤。

      所以說在沒有徹底的了解這個方法之前不要輕易的在自己的項目中使用這個方法。

      接下來咔咔將使用一個案例來演示這個方法的使用,僅僅只是演示使用,如果需要使用到項目中請仔細閱讀文檔應該注意的問題。

      案例演示

      公司有一個業務需要發送通知給用戶,但是由于發送時間太久,非常費時間,有可能需要好幾十秒的時間,更嚴重的會直接導致瀏覽器連接超時。

      在一個問題就是用戶體驗的問題,用戶等待時間過程,體驗當然不好。

      為了解決以上倆個問題,今天談論的fastcgi_finish_request就派上了用場。

      理解

      對這個函數的理解其實就是發送響應給瀏覽器,用戶等待時間大大縮短,但是PHP進程還是在運行的。

      這樣就達到了來個目的,就類似于我們經常說的異步執行。

      直觀的來說就是發送郵件有可能需要10秒,但是用戶是沒有感知的,用戶點擊發送郵件之后直接就返回發送成功,瀏覽器響應結束,用戶做其它事情,后臺進程繼續執行發送郵件的任務。

      案例

      具體代碼

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      以上測試全部使用linux系統進行測試哈,否則你看不到直觀的效果。

      經過上面的演示,響應非常快,瀏覽器響應結束后,后臺程序依然進行執行每秒執行一個時間戳。

      以上就是對fastcgi_finish_request方法的簡單介紹,如果你也感興趣可以進行簡單的嘗試一下,有助于更好的去理解其中的小秘密。

      八、trait特性講解

      應該在倆年前咔咔就對這個特性進行過一次解析,trait就是常說的超類。

      這個特性是在PHP5.4才加入的,這個特性不是經常使用的接口更不是類。

      這個特性是為了解決PHP的一大弱點只能單繼承的缺點,但是也不能叫多繼承,嚴謹一點的就是類似多繼承的功能而已。

      接下來給大家演示一個案例。

      創建test文件一,并且返回對應類名。

      創建test1文件,并且返回對應類名

      創建控制器文件用來輸出信息。

      然后在控制器中引入對應的超類文件,這里需要注意的是圈住的第一個框,這個框就是直接引入超類test文件。

      然后可以直接進行訪問,看會返回什么。

      通過上圖訪問結果結果可以看得到返回的是Test超類文件的方法,但是此控制器同樣也基礎了Controller控制器,這也就是在文章一開頭就說的超類就是實現了一種多繼承的功能而已。

      但是這里會存在一個問題,請看下圖報錯信息。

      上圖的報錯信息是因為在控制器中使用了倆個超類導致的,也就是下圖的使用方式。

      那么如何解決這種報錯信息呢!接下來跟這咔咔的節奏一起來。

      解決報錯信息

      在解決之前問題之前得先清楚這個問題是由于什么引起的。

      出現這個錯誤的原因是引用的兩個trait里面有同名的hello函數,出現了沖突。

      但是在日常開發中這種情況都是可以避免的,因為手動改方法名還是很方便的,但是這里咔咔教大家如何解決這種問題。

      一是用其中一個trait里的hello方法覆蓋另外一個trait的同名方法,因為兩個方法內容是一致的,所以我這里直接選擇insteadof覆蓋;

      二是給他們用as起別名,這樣就不會有沖突了。as關鍵詞還有另外一個用途,那就是修改方法的訪問控制。

      經過上圖的改動之后,再一次的進行訪問,看一下返回結果。

      那么這個時候就會有伙伴有疑問了,就是案例打印結果一直是Test類的方法,Test1類的方法一直沒有進行打印。

      那是如何進行訪問的呢!來接著看一下。

      從上圖可以看到將訪問方法改為了別名控制訪問,接著來看一下訪問結果。

      從上圖中可以可以看到返回結果就是超類Test1類的返回結果。

      那么關于as這個的使用就需要大家在去搜索一下使用方式,有時候注意一下細節就可以學到很多知識點。

      總結

      直到這里關于控制器的源碼解析就到這了,咔咔通過源碼給大家分析控制器的如如何進行實例化的。

      也再一次的進行了對ArrayAccess和魔術方法的調用關系,一定要有自己的思考去想問題。

      在就是對訪問控制器后是如何進行響應數據的,等等。

      也在源碼中學到了關于fastcgi_finish_request方法巧用,但是在使用這個函數一定要注意關于咔咔提到的倆個注意點。

      最后就是對超類的一個簡單案例描述。

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

      NAT ThinkPHP 容器

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:第十一屆藍橋杯省賽JavaC組真題——詳細答案對照(完整版)
      下一篇:Istio技術與實踐07:原理解析Istio調用鏈埋點并非完全非侵入
      相關文章
      WWW国产亚洲精品久久麻豆| 亚洲视频一区二区在线观看| 亚洲av片不卡无码久久| 亚洲成AV人在线播放无码| 国产日产亚洲系列| 亚洲国产V高清在线观看| 色偷偷噜噜噜亚洲男人| 99亚洲乱人伦aⅴ精品| 亚洲精华液一二三产区| 亚洲国产成人精品无码区二本| 亚洲AV无码一区二区三区牛牛| 亚洲另类古典武侠| 亚洲一区二区三区国产精品无码| 亚洲精品永久www忘忧草| 亚洲免费黄色网址| 成人亚洲国产va天堂| 成人亚洲国产va天堂| 亚洲av无一区二区三区| 国产亚洲午夜精品| 亚洲精品tv久久久久久久久久| 亚洲乱码国产一区网址| 久久亚洲欧洲国产综合| 亚洲人成77777在线播放网站| 亚洲精品高清无码视频| 亚洲av午夜成人片精品网站| 亚洲午夜精品一区二区| 亚洲熟妇av一区| 99亚偷拍自图区亚洲| 亚洲欧美国产国产综合一区| 亚洲日韩在线中文字幕综合 | 亚洲七久久之综合七久久| 亚洲精品女同中文字幕| 国产精品亚洲专区在线播放| 亚洲最大av无码网址| 久久久青草青青亚洲国产免观 | 亚洲不卡中文字幕无码| 伊人久久综在合线亚洲2019| 亚洲国产成人精品无码区在线网站| 亚洲AV成人影视在线观看| 校园亚洲春色另类小说合集 | 亚洲国产综合人成综合网站|