--- tags: laravel --- # Laravel請求的生命週期 ![](https://i.imgur.com/2PbLnpA.jpg) ## 介紹 這篇文章將要給你一個清楚且從大局觀去了解到底Laravel框架是如何運作的。越是更好的了解一個框架,當你看到一些方便的效果出現時,就不會認為這是"魔法",同時在運用時也就更有自信 假如下面寫的一些東西你不是太了解,別急著失去信心! 只要先對等會說的有個大概的理解即可,隨著你在學習過後續的章節之後,你將會越來越有概念的 ## 生命週期說明 ![](https://i.imgur.com/rlmnbCN.png) ### 第一步 Laravel應用的所有請求入口為 public/index.php,也就是說任何的請求都會被網頁伺服器(Apache/Nginx)設定導向到這個檔案 這個index.php並沒有太多的程式內容,只不過是用來載入剩下的Laravel框架 index.php檔案載入由Composer自動生成的類別定義,然後從 bootstrap/app.php 傳回一個 Laravel 應用的實例 而Laravel自身做的第一件事情就是建立一個應用或者說是服務容器的實例,接著是綁定實作,如以下程式碼: ``` \\bootstrap/app.php $app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') ); $app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class ); $app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class ); $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class ); ``` 這段程式碼總共做了兩件事情,分別是設定主要目錄以及綁定實作的類別 設定主要目錄是為了方便之後其他工作常需要找子目錄,其路徑自然都需要相對於主要目錄。而綁定實作的類別,之後可以根據需要,去透過Application建置需要的實例來運作 > 現代的網頁應用,除了提供網頁服務外,也會提供命令列或單元測試等功能;一般來說,都會希望不管是透過網頁瀏覽器又或者是透過命令列等不同情境都能呈現出相同的結果。 > 只要Application的初始化有一致,那麼不同情境也會跑相同的程式碼 ### HTTP / Console Kernels 接下來,請求將會被轉給 HTTP Kernel 又或者是 Console Kernel,端視請求的類型來決定。這兩個Kernel作為核心,所有的清求都會經過它們。現在,先聚焦在 HTTP kernel,位於 app/Http/Kernel.php 這個 HTTP Kernerl 繼承了 Illuminate\Foundation\Http\Kernel 類別,這裡定義了一個 bootstrappers 陣列,將會在請求被執行之前先運作。這些 bootstrapper 定義了錯誤處理.log紀錄.偵測應用環境.以及所有需要在請求被執行之前先行運作的工作。一般來說,這些類別會把Laravel的內部設定都搞定好,你不需要自己把手弄髒去做設定 HTTP Kernel也定義了一個 HTTP 中介層清單,使得所有請求需要在被應用處理之前先通過這些中介層,就像是濾網一般。這些中介層處理HTTP Session的讀寫,判斷應用是否處於維護模式,確認CSRF token,還有更多等會會提到的.. HTTP Kernel的 handle() 很簡單: 它接收一個請求,並回傳一個回應。不妨把 HTTP Kernel想成是一個很大的黑箱,代表整個應用,提供它HTTP請求就會傳出HTTP回應 裏頭可以預期的是做了這些事情: 1. 載入.env檔案 2. 載入config設定 3. 設定錯誤處理 4. 設定 Facade 5. 註冊服務供應器(也就是 register 方法) 6. 啟動服務供應器(也就是 boot 方法) > 由此可知所有服務供應器的 register() 會比 boot() 先執行 ### 服務供應器 在所有的 Kernel bootstrapping 行動當中最重要的,莫過於載入你應用的服務供應器。應用的所有服務供應器是被設定於 config/app.php 設定檔裡的 providers 陣列裏頭 Laravel會逐一的遞迴這個列表並生成這些服務供應器實例。當完成初始化,這些供應器的 register() 將會被呼叫。當完成註冊後,這些供應器的 boot() 又會接著被呼叫 服務供應器負責引導框架的各種元件,比如資料庫database,排程queue,驗證validation以及最常用的路由Route元件 可以說所有由Laravel框架所提供的所有主要特色都是由服務供應器來引導並進行設定,因此可說是在整個Laravel引導過程中最重要的部分 你可能會覺得很好奇為什麼服務供應器的 register() 需要優先於 boot() 來執行。其實很簡單,透過先執行 register() 能夠去完成該服務供應器的初始化,以確保接下來的 boot() 能夠正常執行 ### 路由 在這些重要的服務供應器當中,其中的超級明星就是 App\Providers\RouteServiceProvider。這個服務供應器載入了存放專案的routes資料夾裏頭的路由檔案。再接下來,你可以打開看看 RouteServiceProvider.php ,看看它做了些甚麼事情 一旦應用開始引導並註冊了所有的服務供應器,請求將會被轉給路由去處理,再接下來路由又會根據規則來判斷要把這個請求分配給哪一個控制器的哪一個方法來處理,以及是否要執行哪一個中介層等等 中介層提供了一個便利的機制來過濾或者是驗證HTTP請求。舉例來說,Laravel內建了一個中介層用來驗證使用者是否完成登入。假如使用者沒登入的話,中介層會把使用者導到登入頁。反之,如果使用者已經完成登入,中介層就會允許它通過到下一關,直到進入應用裏頭。有些中介層被設計來對應應用裡的所有路由,就像是那些被定義在 HTTP kernal裏頭 $middleware屬性內的,如果想了解更多關於中介層的知識,可以參考中介層那一個章節 假如請求通過了所有對應路由所派發的中介層,對應路由就會將之轉給控制器的方法來接手執行,並且接收控制器方法所回傳的回應,再接著將對應傳回也需要通過路由的中介層鏈 ### 總結 當路由或控制器方法回傳一個回應,回應將會傳回並經過路由的中介層,提供應用能有機會去修改或驗證回應 最後,當回應通過了所有中介層,HTTP核心的處理方法就發出回應物件,而index.php檔案就會呼叫回應的send(),這個send()發出回應內容到使用者網頁瀏覽器 太棒了,我們已經體驗過整個Laravel請求的生命週期囉 ## 專注於服務供應器 服務供應器真的是引導Laravel應用的關鍵。當應用實例被建立之後,服務供應器跟著被註冊,然後請求就一關關的被引導進應用裏頭。就這麼的簡單! 對Larvel應用是如何被建立,而且如何透過服務供應器來引導是很用的。你的應用裡的內建服務供應器都被存放在 app/Providers 資料夾內 預設情況下, AppServiceProvider.php這支檔案裏頭是空的。這個供應器是個很好的地方讓你去加入自己的引導程式以及服務容器綁定。對於大型應用,你也許希望去建立多個服務供應器,每一個服務供應器負責特定的服務 ## 參考資料 [分析bootstrap流程](https://ithelp.ithome.com.tw/articles/10202291?sc=iThelpR) [Request Lifecycle](https://laravel.com/docs/8.x/lifecycle)