與 Laravel 10 以前的比較
Laravel 11 以「Slim Application Skeleton」為名,大幅刷新了應用程式結構。最大的變化是消除設定的分散,集中至bootstrap/app.php 一處。
此變更針對新專案。既有的 Laravel 10 應用程式升級後,舊有結構仍可原樣運作。
新的目錄與檔案結構
Skeleton 的目錄結構
bootstrap/app.php — 應用程式設定的中心
app/Http/Kernel.php、app/Console/Kernel.php、app/Exceptions/Handler.php 三個檔案的設定,現在都集中在此。
bootstrap/providers.php — 服務提供者清單
config/app.php 的 providers 陣列,現已分離至 bootstrap/providers.php。Laravel 11 的預設僅有 AppServiceProvider。
routes/ 目錄的變更
api.php 與 channels.php。可依需求以 Artisan 指令產生。
routes/console.php 中也可以定義排程。
已廢除的檔案
app/Http/Kernel.php 的廢除
app/Http/Kernel.php 的廢除
HTTP Kernel 已整合至框架內部的
Illuminate\Foundation\Http\Kernel。中介層的自訂改在 bootstrap/app.php 的 withMiddleware() 中進行。app/Console/Kernel.php 的廢除
app/Console/Kernel.php 的廢除
Console Kernel 的兩項職責已被分離。Artisan 指令置於
app/Console/Commands/ 會被自動偵測,排程則寫在 routes/console.php。app/Exceptions/Handler.php 的廢除
app/Exceptions/Handler.php 的廢除
例外處理器已整合至框架內部的
Illuminate\Foundation\Exceptions\Handler。自訂改在 bootstrap/app.php 的 withExceptions() 中進行。Application::configure() 的運作機制
框架內部的實作
Application::configure() 是 Illuminate\Foundation\Application 的靜態方法。
- 依
basePath決定應用程式的根目錄 - 建立
Application實例 - 以
ApplicationBuilder包裝,套用預設設定 - 回傳
ApplicationBuilder實例
configure() 內已呼叫了 withKernels() / withEvents() / withCommands() / withProviders()。在 bootstrap/app.php 中無需再次呼叫。
以方法鏈進行設定的流程
create() 後從 ApplicationBuilder 取出 Application 實例,而 bootstrap/app.php 所 return 的即是此 Application 實例。
從請求到應用程式啟動的流程
public/index.php 為進入點,載入 bootstrap/app.php 以取得 Application。之後 HTTP Kernel 將請求通過中介層的 Pipeline,Router 再派送至 Controller。
ApplicationBuilder 主要方法深入探討
withRouting() — 路由註冊的內部處理
AppRouteServiceProvider::loadRoutesUsing(),並在應用程式 booting 時註冊 AppRouteServiceProvider。
api路由會自動套用api中介層群組及/api前綴- 若傳入字串至
health,會自動註冊健康檢查端點(預設/up) health的路徑在維護模式下也會被排除(透過PreventRequestsDuringMaintenance::except()設定)- 請注意
api會比web先註冊。若同一路徑同時定義 Web 與 API 路由,會以 API 路由優先 - 若傳入字串至
pages,則會啟用 Laravel Folio 的路由
withMiddleware() — 中介層自訂
withMiddleware() 是在 HttpKernel 被解析之後執行 callback。這是因為使用了 afterResolving() hook。傳入 callback 的 Middleware 物件擁有豐富的自訂方法。
withExceptions() — 例外處理設定
withExceptions() 會先將框架的 Handler 類別註冊為 singleton,再以 afterResolving() 設定 callback。傳給 callback 的是 Exceptions wrapper 物件。
withProviders() — 服務提供者註冊
withProviders() 於 Application::configure() 內已預設呼叫,bootstrap/providers.php 會自動被載入。若要加入額外的提供者,需在 bootstrap/app.php 中明確呼叫。
其他主要方法
設計意圖:為什麼如此設計
「Code First」的設定
Laravel 10 以前的app/Http/Kernel.php 採以陣列列舉中介層的方式。這種寫法接近設定檔,缺點是不易獲得 PHP 型別系統及 IDE 的支援。
Laravel 11 改為 withMiddleware(function (Middleware $middleware) { ... }) 的 callback 風格。如此便可享有型別補完,也能自然地寫出使用條件分支或迴圈等邏輯的動態設定。
從「慣例優於設定」到「明確的設定」
api.php 之所以改為選用,是為了解決即便應用程式未使用 API 路由,api 中介層群組仍會一直被載入的問題。方針是:預設不存在不使用的功能。
afterResolving() hook 的活用
withMiddleware() 與 withExceptions() 中使用 afterResolving(),是為了避免設定順序上的問題。ApplicationBuilder 的方法會在應用程式完全啟動前呼叫,實際的處理(對 Kernel 套用設定)則在 Kernel 首次被解析時延遲執行。
自訂範例
讓 API 與 Web 並存
中介層的自訂
將排程集中至 bootstrap/app.php
排程亦可寫在 routes/console.php,但使用 withSchedule() 可將其集中於 bootstrap/app.php。
例外處理的自訂
於 bootstrap/app.php 管理 Container 綁定
若為小型應用程式,也可將簡單的綁定寫在 bootstrap/app.php 而非 AppServiceProvider。
Laravel 啟動流程的順序
Laravel 應用程式啟動時,服務提供者與 Application 的 hook 按下列順序執行。- 執行所有 ServiceProvider 的
register() - Application 的
registered() - Application 的
booting() - 執行所有 ServiceProvider 的
boot() - Application 的
booted()
AppServiceProvider 加入下列程式碼即可確認執行順序。
ApplicationBuilder 的 registered()、booting()、booted() 只是向 Application 註冊 callback 的方法。通常不需使用,但可用於例如在 booted() 中對啟動準備完成的 Kernel 進行變更等特殊操作。
下一步
服務容器
了解
ApplicationBuilder 內部所使用的服務容器機制。新應用結構 FAQ
彙整新應用程式結構的常見疑問與解答。