溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ThinkPHP框架執(zhí)行流程是怎么樣的

發(fā)布時(shí)間:2020-12-30 10:30:45 來源:億速云 閱讀:324 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關(guān)ThinkPHP框架執(zhí)行流程是怎么樣的的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

ThinkPHP框架執(zhí)行流程是怎么樣的

執(zhí)行流程圖

一、框架執(zhí)行流程之初始化應(yīng)用的數(shù)據(jù)設(shè)置

這里的內(nèi)容跟容器的內(nèi)容有點(diǎn)重復(fù),因?yàn)閳?zhí)行流程是從入口文件開始的,并且最后也是通過容器執(zhí)行的。

ThinkPHP框架執(zhí)行流程是怎么樣的

入口文件

然后就會(huì)進(jìn)入到文件thinkphp/library/think/App.php的run方法,在這個(gè)方法中主要就是下圖框出來的地方,執(zhí)行的initialize方法。

ThinkPHP框架執(zhí)行流程是怎么樣的

來到initialize這個(gè)方法,先看上半部分。

  • microtime(true);返回的是unix的微秒數(shù)
  • memory_get_usage返回的是分配給PHP的內(nèi)存量,單位為字節(jié)
  • 在接下來就是對(duì)框架的幾個(gè)路徑進(jìn)行設(shè)置
  • static::setInstance($this);這里是將app這個(gè)實(shí)例設(shè)置為容器實(shí)例
  • $this->instance('app', $this);這個(gè)在之前容器章節(jié)就提到了,就是為了把a(bǔ)pp這個(gè)類綁定到容器里邊去,也就是注冊(cè)樹模式。


ThinkPHP框架執(zhí)行流程是怎么樣的

這里有一個(gè)小的問題點(diǎn)給大家提出來,在初始化應(yīng)用的這個(gè)方法里邊存在這樣一行代碼。

有沒有小伙伴對(duì)這個(gè)$this->env和下邊的$this->config這倆個(gè)調(diào)用有疑惑。

如果你有疑惑那就跟著咔咔一起來看,沒疑惑的就可以繼續(xù)往下看了。

App這個(gè)類是繼承的容器類,那么這個(gè)env和config不論是在app還是container類中都是沒有這倆個(gè)屬性的。

那么怎么就可以直接調(diào)用呢!而且代碼追蹤都會(huì)追蹤到env類和container類中。

需要知道這個(gè)源頭就需要我們?nèi)ピ诖笾碌目匆槐閏ontainer類的代碼。

ThinkPHP框架執(zhí)行流程是怎么樣的

解決疑惑,為什么可以這樣使用

經(jīng)過一番苦讀之后,可以看到下圖的幾行代碼。這幾行代碼全部使用的是魔術(shù)方法。

當(dāng)訪問env類不存在的時(shí)候就會(huì)去執(zhí)行make方法。

make這個(gè)方法在容器那一章節(jié)進(jìn)行的細(xì)的不能再細(xì)的解讀了。

這個(gè)make方法最終會(huì)返回一個(gè)類的實(shí)例,并且還會(huì)存到容器里邊。

ThinkPHP框架執(zhí)行流程是怎么樣的

這里只放一個(gè)make方法的代碼,如果有不會(huì)的可以去看之前的文章。

ThinkPHP框架執(zhí)行流程是怎么樣的

最后就是加載一系列的數(shù)據(jù),加載詳情請(qǐng)看前言的思維導(dǎo)圖。

ThinkPHP框架執(zhí)行流程是怎么樣的

執(zhí)行加載

二、如何查看一個(gè)方法都在哪里執(zhí)行了

在閱讀源碼的過程中,有一個(gè)很難把控的問題就是一個(gè)方法在不同的地方進(jìn)行了調(diào)用,但是咱們確一時(shí)半會(huì)根本不知道都在哪里調(diào)用了。

這里用init方法來做一個(gè)演示。

init方法是初始化應(yīng)用或者模塊的一個(gè)方法,但是這里的module參數(shù)確實(shí)一個(gè)空值。

ThinkPHP框架執(zhí)行流程是怎么樣的先做一個(gè)斷點(diǎn)查看一下相關(guān)的數(shù)據(jù)信息。

打印的結(jié)果就是空,這就是一些新學(xué)習(xí)的伙伴會(huì)犯的一個(gè)錯(cuò)誤,因?yàn)檫@個(gè)方法不可能只調(diào)用一次的。

如果初始化模塊都是空那么這個(gè)方法就沒有存在的必要了。

ThinkPHP框架執(zhí)行流程是怎么樣的ThinkPHP框架執(zhí)行流程是怎么樣的那么正確的斷點(diǎn)方式應(yīng)該是這個(gè)樣子的。

ThinkPHP框架執(zhí)行流程是怎么樣的ThinkPHP框架執(zhí)行流程是怎么樣的此時(shí)就會(huì)有一個(gè)問題,這個(gè)init方法明顯是被調(diào)用了倆次的,那么另一次調(diào)用的地方是在哪里呢!

如果在不知道新的技巧之前,就會(huì)進(jìn)行一系列的斷點(diǎn)打印,看在哪里進(jìn)行了執(zhí)行,比如在這個(gè)init的上層去打印。

也就是在initialize那個(gè)方法里邊去打印做斷點(diǎn),但是這樣很是麻煩的,而且很有可能浪費(fèi)了大量的時(shí)間還是找不到正確的地方。

小技巧之debug_backtrace()

這個(gè)方法會(huì)產(chǎn)生一條回溯追蹤,會(huì)顯示出一個(gè)方法所有的調(diào)用位置。

使用方式就是如下圖,只需要把debug_backtrace這個(gè)方法打印出來即可。

ThinkPHP框架執(zhí)行流程是怎么樣的ThinkPHP框架執(zhí)行流程是怎么樣的ThinkPHP框架執(zhí)行流程是怎么樣的

根據(jù)得到的數(shù)據(jù)信息,就可以非常快的進(jìn)行定位。

第一次就是在app類的215行。

ThinkPHP框架執(zhí)行流程是怎么樣的


第一次調(diào)用init的地方

第二次是在thinkphp/library/think/route/dispatch/Module.php類的60行

ThinkPHP框架執(zhí)行流程是怎么樣的

第二次調(diào)用地方

可以在這里做一個(gè)打印,看一下這個(gè)module是否為index

ThinkPHP框架執(zhí)行流程是怎么樣的ThinkPHP框架執(zhí)行流程是怎么樣的所以說有了這個(gè)方法就可以非??焖俚囟ㄎ徽{(diào)用位置。

三、框架執(zhí)行流程之初始化應(yīng)用init分析

上文給大家提供了一個(gè)小技巧debug_backtrace實(shí)戰(zhàn)演示了如何查看一個(gè)方法都在哪里執(zhí)行的。

并且案例也是使用的init這個(gè)方法來演示的,因?yàn)榻酉聛砭褪且獙?duì)init這個(gè)方法進(jìn)行深入的了解。

在init方法里邊主要做的事情在上邊的腦圖已經(jīng)描述的很清楚了。

  • 從一開始就對(duì)模塊的定位,就是在第二節(jié)中的對(duì)init方法的調(diào)用,會(huì)傳入對(duì)應(yīng)的模塊
  • 加載app目錄下的tags文件,在tags文件里邊就是對(duì)行為擴(kuò)展定義的文件。在之前門面的文章中定義鉤子執(zhí)行就在這個(gè)文件中設(shè)置的。
  • 加載common文件,也就是公共文件,所以說公共文件就是在這里進(jìn)行加載的。
  • 加載助手函數(shù)文件helper,在助手函數(shù)里邊有一個(gè)大家特別熟悉的一個(gè)方法,那就是dump。這就是為什么在有的地方使用dump會(huì)報(bào)錯(cuò)的原因。
  • 加載中間件文件,這里的直接給出的是直接加載app目錄下的中間件文件,但是在框架中我們需要在定義一個(gè)目錄為http,在這個(gè)目錄下定義中間件文件。
  • 注冊(cè)服務(wù)的容器對(duì)象實(shí)例,這里注冊(cè)就使用的是容器類中的bindTo方法進(jìn)行綁定注冊(cè)的。
  • 讀取配置文件,這段在配置文件加載那一節(jié)中已經(jīng)進(jìn)行深入的說明了, 這里就不提了。配置文件會(huì)讀取倆個(gè)地方一個(gè)是第一步模塊下的config文件,另一個(gè)就是config目錄下的配置文件。
  • 設(shè)置模塊路徑,會(huì)把第一步獲取到的模塊進(jìn)行env環(huán)境變量配置里邊
  • 最后一步就是對(duì)容器中的對(duì)象實(shí)例進(jìn)行配置更新,具體更新了什么在后文中給大家詳細(xì)說來。
    /**     * 初始化應(yīng)用或模塊     * @access public     * @param  string $module 模塊名     * @return void     */    public function init($module = '')    {        // 定位模塊目錄        $module = $module ? $module . DIRECTORY_SEPARATOR : '';        /**         * 第一次:D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\         * 第二次:D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\         */        $path   = $this->appPath . $module;        // 加載初始化文件        if (is_file($path . 'init.php')) {            include $path . 'init.php';        } elseif (is_file($this->runtimePath . $module . 'init.php')) {            include $this->runtimePath . $module . 'init.php';        } else {            // 加載行為擴(kuò)展文件            if (is_file($path . 'tags.php')) {                $tags = include $path . 'tags.php';                if (is_array($tags)) {                    $this->hook->import($tags);                }            }            // 加載公共文件            if (is_file($path . 'common.php')) {                include_once $path . 'common.php';            }            if ('' == $module) {                // 加載系統(tǒng)助手函數(shù)                include $this->thinkPath . 'helper.php';            }            // 加載中間件            if (is_file($path . 'middleware.php')) {                $middleware = include $path . 'middleware.php';                if (is_array($middleware)) {                    $this->middleware->import($middleware);                }            }            // 注冊(cè)服務(wù)的容器對(duì)象實(shí)例            if (is_file($path . 'provider.php')) {                $provider = include $path . 'provider.php';                if (is_array($provider)) {                    $this->bindTo($provider);                }            }            /**             * $path : "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\"             *          "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\"             */            // 自動(dòng)讀取配置文件            if (is_dir($path . 'config')) {                $dir = $path . 'config' . DIRECTORY_SEPARATOR;            } elseif (is_dir($this->configPath . $module)) {                // D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\config\                $dir = $this->configPath . $module;            }            // scandir:以升序的方式讀取目錄中的文件            // 返回就是config目錄中的所有文件            $files = isset($dir) ? scandir($dir) : [];            foreach ($files as $file) {                /**                 * $this->configExt:配置文件的后綴                 * pathinfo返回的是文件后綴,關(guān)于pathinfo共有三個(gè)可選的參數(shù)PATHINFO_DIRNAME、PATHINFO_BASENAME、PATHINFO_EXTENSION,分別為只返回文件名,文件目錄名,文件擴(kuò)展                 */                if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $this->configExt) {                    /**                     * 倆個(gè)參數(shù)分別為                     * 1.目錄+config目錄下的文件                     * 2.config目錄下文件名                     */                    $this->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME));                }            }        }        $this->setModulePath($path);        if ($module) {            // 對(duì)容器中的對(duì)象實(shí)例進(jìn)行配置更新            $this->containerConfigUpdate($module);        }    }

這里附帶上一份代碼,可以對(duì)著代碼看上邊的執(zhí)行流程,對(duì)每一步都做了簡(jiǎn)單的說明。

咔咔個(gè)人見解對(duì)源碼進(jìn)行優(yōu)化

在設(shè)置模塊的這步代碼咔咔感覺不是很是嚴(yán)謹(jǐn),因?yàn)閕nit方法會(huì)在倆個(gè)地方進(jìn)行執(zhí)行。

第一次的模塊為空,這塊代碼執(zhí)行是沒有任何意義的。

下面在對(duì)容器的對(duì)象實(shí)例進(jìn)行配置更新時(shí)進(jìn)行了一次判斷,判斷模塊的這個(gè)參數(shù)是否為空,如果不為空才會(huì)執(zhí)行。

那么同樣的道理,咔咔感覺在設(shè)置模塊路徑這塊也應(yīng)該在這個(gè)判斷里邊。

雖說第二次執(zhí)行會(huì)把第一次的結(jié)果覆蓋掉,但是咔咔感覺下圖這樣使用才會(huì)更好。

ThinkPHP框架執(zhí)行流程是怎么樣的


咔咔對(duì)源碼修改建議

四、對(duì)容器中的對(duì)象實(shí)例進(jìn)行更新配置

在上一節(jié)中這里就是最后的內(nèi)容,那這個(gè)對(duì)實(shí)例進(jìn)行更新配置,到底更新了什么,怎么更新沒有說明。

在這一小節(jié)中就會(huì)做出說明,同樣可以配合著前言的思維導(dǎo)圖看。

  • 先會(huì)把config目錄下的所有配置信息全部獲取出來
  • 從app配置文件中將注冊(cè)異常處理類
  • 第三大塊是把第一步獲取出來的所有配置信息給對(duì)應(yīng)的類進(jìn)行注冊(cè)配置。
  • 第四步就是在把模塊確定下來之后加載對(duì)應(yīng)的語言包,語言包功能就可以實(shí)現(xiàn)多語言功能,之前咔咔寫過一篇文章實(shí)現(xiàn)多語言功能,如果感興趣的可以去查看。
  • 最后一步就是根據(jù)app配置文件中的三個(gè)屬性進(jìn)行緩存的處理

在這一節(jié)中咔咔感覺最重要的就是下圖的內(nèi)容了。

ThinkPHP框架執(zhí)行流程是怎么樣的我們可以隨意追蹤一到倆個(gè)方法查看一下那邊到底執(zhí)行了什么方法。

追蹤方法Db::init()

追蹤方法過來后可以看到就是對(duì)Db類中的config屬性進(jìn)行賦值,把database中的值賦值給Db類中的config屬性。

ThinkPHP框架執(zhí)行流程是怎么樣的追蹤方法$this->middleware->setConfig()

來到中間件這個(gè)類里邊,可以看到就是把本類的配置和傳遞過來的參數(shù)類進(jìn)行合并,同樣也是進(jìn)行config屬性的賦值。

跟上邊案例的Db類的init方法實(shí)現(xiàn)的效果是一致的。

這里在提一嘴就是在對(duì)容器中的對(duì)象實(shí)例進(jìn)行更新配置這一幅圖中可以看到紫色部分是在本類中沒有引用的。

那么這是怎么可以進(jìn)行執(zhí)行的呢!是因?yàn)锳pp類繼承了容器類,容器類中有四個(gè)魔術(shù)方法,其中有一個(gè)__get方法,就是在獲取不存在的屬性時(shí)會(huì)執(zhí)行那個(gè)方法。

在魔術(shù)方法__get方法中執(zhí)行了一個(gè)make方法,這個(gè)make方法說了好多次了,這個(gè)方法最終會(huì)返回一個(gè)應(yīng)用的實(shí)例,然后用這個(gè)實(shí)例調(diào)用對(duì)應(yīng)實(shí)例類的方法。

這一塊一定要理解好,閱讀源碼就是這個(gè)樣子,我們需要對(duì)一切未知的進(jìn)行的解決,只有這樣才能提高我們的編程能力和思想。

ThinkPHP框架執(zhí)行流程是怎么樣的


中間件的設(shè)置配置

五、淺談?wù){(diào)試模式以及代碼冗余

本節(jié)會(huì)對(duì)調(diào)試模式做出簡(jiǎn)單的說明,并且會(huì)對(duì)框架代碼冗余情況進(jìn)行簡(jiǎn)單的提出。

沒有人寫的代碼是沒有漏洞的,如果有那就是你還沒有達(dá)到一定的造詣。

調(diào)試模式

在第一節(jié)中只提到了initialize方法的上半部分,因?yàn)樵谶@一節(jié)之前聊的都是關(guān)于應(yīng)用初始化init的內(nèi)容。

接下來會(huì)對(duì)這一塊的內(nèi)容進(jìn)行簡(jiǎn)單的說明。

  • 從app配置文件中獲取到app_debug的配置項(xiàng)
  • 給環(huán)境變量設(shè)置debug級(jí)別
  • 當(dāng)框架中的debug是關(guān)閉狀態(tài)時(shí)會(huì)執(zhí)行ini_set這個(gè)方法,這個(gè)方法是為一個(gè)配置選項(xiàng)進(jìn)行賦值。

接下來的內(nèi)容估計(jì)不是很好理解,都是平時(shí)在工作中根本使用不到的。

  • ob_get_level:返回輸出緩沖機(jī)制的嵌套級(jí)別,那么怎么去理解呢!其實(shí)就是當(dāng)緩存區(qū)不起作用時(shí)會(huì)返回0。
  • ob_get_clean:這個(gè)函數(shù)將會(huì)返回輸出緩沖的內(nèi)容并終止輸出緩沖。如果緩沖區(qū)沒有有效內(nèi)容則返回false。本質(zhì)上相當(dāng)于同時(shí)執(zhí)行了ob_getcontens()和ob_end_clean()。
  • ob_start:打開輸出控制緩沖

上邊這三個(gè)先暫時(shí)認(rèn)識(shí)就行,后期如果有機(jī)會(huì)會(huì)專門出一篇文章做解釋的。

ThinkPHP框架執(zhí)行流程是怎么樣的關(guān)于框架代碼冗余

這里也僅僅代表咔咔個(gè)人的觀點(diǎn)。

可以先看看這部分的代碼,這倆處代碼是不是很是熟悉,沒錯(cuò)就是在上文的init方法中容器對(duì)象實(shí)例配置更新見到過。

ThinkPHP框架執(zhí)行流程是怎么樣的如圖

ThinkPHP框架執(zhí)行流程是怎么樣的這塊也就是咔咔個(gè)人提出的見解,由于咔咔式針對(duì)5.1做的源碼解讀,不太了解新版版是否做出了改動(dòng)。

六、總結(jié)

本節(jié)主要是針對(duì)框架執(zhí)行流程中的初始化應(yīng)用做了簡(jiǎn)單的探討。

至于在app類的run方法下面還有很多的執(zhí)行過程在這一節(jié)中沒有做過多的解釋。

在閱讀源碼的過程中給大家提了一個(gè)很好得小技巧,那就是如何去查看一個(gè)方法都在哪里進(jìn)行了執(zhí)行。

這個(gè)方法為debug_backtrace,這個(gè)方法需要大家多使用幾次就知道怎么使用了,因?yàn)樵诖蛴〕鰜淼慕Y(jié)果中也存在很多無用的信息。

這個(gè)方法在調(diào)試源碼的過程中是非常有效的,一定要好好利用這個(gè)方法。

在就是對(duì)初始化應(yīng)用init方法進(jìn)行了特別詳細(xì)的介紹。

其中咔咔感覺這塊設(shè)計(jì)最好的就是在容器中的對(duì)象實(shí)例進(jìn)行更新配置那一塊,先讀取所有的配置,然后在通過各個(gè)類的方法進(jìn)行配置的設(shè)置。

這種代碼規(guī)劃和設(shè)計(jì)思路值得我們?nèi)W(xué)習(xí)。

最后聊到了調(diào)試模式和框架的代碼冗余問題,關(guān)于調(diào)試模式這里咔咔給大家提個(gè)醒項(xiàng)目在線上的調(diào)試模式一定要關(guān)閉。

否則你的項(xiàng)目就類似于裸奔的存在,沒有一點(diǎn)點(diǎn)的安全可言。

這塊有點(diǎn)不好理解的就是對(duì)于緩沖區(qū),關(guān)于這塊的內(nèi)容咔咔認(rèn)為暫時(shí)沒有必要去鉆牛角尖,先認(rèn)識(shí)認(rèn)識(shí)然后在進(jìn)行深入的研究。

緩沖區(qū)的這塊內(nèi)容估計(jì)工作了三四年的也很少有人使用,所以先認(rèn)識(shí),知道怎么一回事,咔咔后期學(xué)習(xí)了之后在給大家進(jìn)行補(bǔ)充。

直到這里關(guān)于框架的執(zhí)行流程之初始化應(yīng)用就結(jié)束了,這一節(jié)沒有過深需要學(xué)習(xí)的,主要是其中的代碼設(shè)計(jì)模式和實(shí)現(xiàn)思路。

最后這個(gè)圖大家一定要跟著源碼看一看哈!

ThinkPHP框架執(zhí)行流程是怎么樣的

在這里插入圖片描述

感謝各位的閱讀!關(guān)于“ThinkPHP框架執(zhí)行流程是怎么樣的”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI