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

本文會對實例化控制器為引子然后解析關于ArrayAccess和直接執行魔術訪問返回實例的區別

前言

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

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

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

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

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

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

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

一、實例化控制器

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

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

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

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

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

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

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

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

立即學習PHP免費學習筆記(深入)”;

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

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

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

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

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

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

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

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

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

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

對抽象類做出解釋

  • 抽象類不能被實例化
  • 有抽象方法的類一定是抽象類;類必須要abstract修飾
  • 抽象方法不能有函數體;即abstract function fun();
  • 抽象類中的非抽象方法,可以被子類調用
  • 非抽象子類繼承抽象類,子類必須實現父類的所有抽象方法
  • 抽象子類繼承抽象類,無需繼承父類的抽象方法

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

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

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

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

怎么去找誰繼承了Dispatch

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

參數說明

  • $name = String(22) “behaviorLoadBehavior”
  • $tag = module_init

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

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

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

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

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

最后這段代碼會返回NULL

實例化控制器

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

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

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

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

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

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

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

先聊ArrayAccess的使用

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

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

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

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

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

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

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

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

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

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

總結

在第一次案例的實現過程中,忽略了一步,就是使用對象直接以數組形式直接訪問對象的屬性。

可以看到的是可以直接獲取到的,那么接下來將這個思想套到框架中在來看一下。

框架實戰案例

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

__get方法使用詳解

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

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

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

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

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

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

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

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

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

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

總結

所以說是用ArrayAccess和__get魔術方法,最終都是執行的make方法返回類的實例。

當遇到this->config就是執行的容器的__get方法。

當遇到app[‘request’]就是執行的ArrayAccess然后執行offsetGet

  • __get是針對類的屬性,當類的屬性不存在時會執行
  • ArrayAccess當是用實例化好的類以數組形式訪問時,如果不存在就會執行offsetGet這個方法。
    推薦教程:《thinkphp

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享