溫馨提示×

溫馨提示×

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

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

ThinkPHP框架的執(zhí)行流程有哪些

發(fā)布時間:2021-06-30 14:54:13 來源:億速云 閱讀:220 作者:Leah 欄目:編程語言

這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān)ThinkPHP框架的執(zhí)行流程有哪些,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

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

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

ThinkPHP框架的執(zhí)行流程有哪些

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

ThinkPHP框架的執(zhí)行流程有哪些 來到initialize這個方法,先看上半部分。

  • microtime(true);返回的是unix的微秒數(shù)

  • memory_get_usage返回的是分配給PHP的內(nèi)存量,單位為字節(jié)

  • 在接下來就是對框架的幾個路徑進行設(shè)置

  • static::setInstance($this);這里是將app這個實例設(shè)置為容器實例

  • $this->instance('app', $this);這個在之前容器章節(jié)就提到了,就是為了把app這個類綁定到容器里邊去,也就是注冊樹模式。

ThinkPHP框架的執(zhí)行流程有哪些 這里有一個小的問題點給大家提出來,在初始化應(yīng)用的這個方法里邊存在這樣一行代碼。

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

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

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

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

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

ThinkPHP框架的執(zhí)行流程有哪些

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

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

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

這個make方法最終會返回一個類的實例,并且還會存到容器里邊。

ThinkPHP框架的執(zhí)行流程有哪些 這里只放一個make方法的代碼,如果有不會的可以去看之前的文章。

ThinkPHP框架的執(zhí)行流程有哪些 最后就是加載一系列的數(shù)據(jù),加載詳情請看前言的思維導(dǎo)圖。

ThinkPHP框架的執(zhí)行流程有哪些

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

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

這里用init方法來做一個演示。

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

ThinkPHP框架的執(zhí)行流程有哪些 先做一個斷點查看一下相關(guān)的數(shù)據(jù)信息。

打印的結(jié)果就是空,這就是一些新學(xué)習的伙伴會犯的一個錯誤,因為這個方法不可能只調(diào)用一次的。

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

ThinkPHP框架的執(zhí)行流程有哪些 ThinkPHP框架的執(zhí)行流程有哪些 那么正確的斷點方式應(yīng)該是這個樣子的。

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

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

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

小技巧之debug_backtrace()

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

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

ThinkPHP框架的執(zhí)行流程有哪些 ThinkPHP框架的執(zhí)行流程有哪些 ThinkPHP框架的執(zhí)行流程有哪些

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

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

ThinkPHP框架的執(zhí)行流程有哪些

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

ThinkPHP框架的執(zhí)行流程有哪些

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

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

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

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

并且案例也是使用的init這個方法來演示的,因為接下來就是要對init這個方法進行深入的了解。

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

  • 從一開始就對模塊的定位,就是在第二節(jié)中的對init方法的調(diào)用,會傳入對應(yīng)的模塊

  • 加載app目錄下的tags文件,在tags文件里邊就是對行為擴展定義的文件。在之前門面的文章中定義鉤子執(zhí)行就在這個文件中設(shè)置的。

  • 加載common文件,也就是公共文件,所以說公共文件就是在這里進行加載的。

  • 加載助手函數(shù)文件helper,在助手函數(shù)里邊有一個大家特別熟悉的一個方法,那就是dump。這就是為什么在有的地方使用dump會報錯的原因。

  • 加載中間件文件,這里的直接給出的是直接加載app目錄下的中間件文件,但是在框架中我們需要在定義一個目錄為http,在這個目錄下定義中間件文件。

  • 注冊服務(wù)的容器對象實例,這里注冊就使用的是容器類中的bindTo方法進行綁定注冊的。

  • 讀取配置文件,這段在配置文件加載那一節(jié)中已經(jīng)進行深入的說明了, 這里就不提了。配置文件會讀取倆個地方一個是第一步模塊下的config文件,另一個就是config目錄下的配置文件。

  • 設(shè)置模塊路徑,會把第一步獲取到的模塊進行env環(huán)境變量配置里邊

  • 最后一步就是對容器中的對象實例進行配置更新,具體更新了什么在后文中給大家詳細說來。

    /**
     * 初始化應(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 {
            // 加載行為擴展文件
            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);
                }
            }

            // 注冊服務(wù)的容器對象實例
            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\"
             */
            // 自動讀取配置文件
            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共有三個可選的參數(shù)PATHINFO_DIRNAME、PATHINFO_BASENAME、PATHINFO_EXTENSION,分別為只返回文件名,文件目錄名,文件擴展
                 */
                if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $this->configExt) {
                    /**
                     * 倆個參數(shù)分別為
                     * 1.目錄+config目錄下的文件
                     * 2.config目錄下文件名
                     */
                    $this->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME));
                }
            }
        }

        $this->setModulePath($path);

        if ($module) {
            // 對容器中的對象實例進行配置更新
            $this->containerConfigUpdate($module);
        }
    }

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

咔咔個人見解對源碼進行優(yōu)化

在設(shè)置模塊的這步代碼咔咔感覺不是很是嚴謹,因為init方法會在倆個地方進行執(zhí)行。

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

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

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

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

ThinkPHP框架的執(zhí)行流程有哪些

四、對容器中的對象實例進行更新配置

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

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

  • 先會把config目錄下的所有配置信息全部獲取出來

  • 從app配置文件中將注冊異常處理類

  • 第三大塊是把第一步獲取出來的所有配置信息給對應(yīng)的類進行注冊配置。

  • 第四步就是在把模塊確定下來之后加載對應(yīng)的語言包,語言包功能就可以實現(xiàn)多語言功能,之前咔咔寫過一篇文章實現(xiàn)多語言功能,如果感興趣的可以去查看。

  • 最后一步就是根據(jù)app配置文件中的三個屬性進行緩存的處理

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

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

追蹤方法Db::init()

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

ThinkPHP框架的執(zhí)行流程有哪些 追蹤方法$this->middleware->setConfig()

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

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

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

那么這是怎么可以進行執(zhí)行的呢!是因為App類繼承了容器類,容器類中有四個魔術(shù)方法,其中有一個__get方法,就是在獲取不存在的屬性時會執(zhí)行那個方法。

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

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

ThinkPHP框架的執(zhí)行流程有哪些

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

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

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

調(diào)試模式

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

接下來會對這一塊的內(nèi)容進行簡單的說明。

  • 從app配置文件中獲取到app_debug的配置項

  • 給環(huán)境變量設(shè)置debug級別

  • 當框架中的debug是關(guān)閉狀態(tài)時會執(zhí)行ini_set這個方法,這個方法是為一個配置選項進行賦值。

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

  • ob_get_level:返回輸出緩沖機制的嵌套級別,那么怎么去理解呢!其實就是當緩存區(qū)不起作用時會返回0。

  • ob_get_clean:這個函數(shù)將會返回輸出緩沖的內(nèi)容并終止輸出緩沖。如果緩沖區(qū)沒有有效內(nèi)容則返回false。本質(zhì)上相當于同時執(zhí)行了ob_getcontens()和ob_end_clean()。

  • ob_start:打開輸出控制緩沖

上邊這三個先暫時認識就行,后期如果有機會會專門出一篇文章做解釋的。

ThinkPHP框架的執(zhí)行流程有哪些 關(guān)于框架代碼冗余

這里也僅僅代表咔咔個人的觀點。

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

ThinkPHP框架的執(zhí)行流程有哪些 如圖

ThinkPHP框架的執(zhí)行流程有哪些 這塊也就是咔咔個人提出的見解,由于咔咔式針對5.1做的源碼解讀,不太了解新版版是否做出了改動。

六、總結(jié)

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

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

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

這個方法為debug_backtrace,這個方法需要大家多使用幾次就知道怎么使用了,因為在打印出來的結(jié)果中也存在很多無用的信息。

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

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

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

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

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

否則你的項目就類似于裸奔的存在,沒有一點點的安全可言。

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

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

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

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

ThinkPHP框架的執(zhí)行流程有哪些


上述就是小編為大家分享的ThinkPHP框架的執(zhí)行流程有哪些了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

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

AI