關於本頁
在套件開發基礎中介紹了只要在composer.json 撰寫 extra.laravel 段落,服務提供者與 Facade 便會自動註冊。本頁將於原始碼層面解說其背後 Illuminate\Foundation\PackageManifest 類別的運作方式。
本頁為套件開發基礎的姊妹頁。建議先閱讀自動偵測的基本使用方式。
自動偵測機制的整體樣貌
PackageManifest 類別
自動偵測的核心是 Illuminate\Foundation\PackageManifest。以下為框架 13.x 時的實作(摘要)。
- manifest 讀入一次後會快取於記憶體(
$this->manifest屬性)。單一請求內即便多次呼叫providers()也僅有 1 次 file I/O。 - 僅在 manifest 檔案不存在時執行
build()。一般營運中並非每次都會建置。 - 實體只是
return一個樸素 PHP 陣列的檔案(bootstrap/cache/packages.php),僅需require即可以最快的形式讀取。
Manifest 的建置處理
build() 方法為實際彙整 composer.json 資訊的部分。
composer.json,而是讀取 vendor/composer/installed.json。這是 Composer 於執行 composer install / composer update 時產生的、包含所有已安裝套件 metadata 的檔案。因為各套件 composer.json 中的 extra 段落已彙整於此,Laravel 端只信任並讀取 Composer 管轄下的資訊。
installed.json 一般會被 .gitignore,因此於初次設定時(尚無 vendor/ 之狀態)自動偵測無法運作。要於 composer install 完成後才會首次建置快取。dont-discover 的兩種寫法
dont-discover 於套件端或應用程式端的 composer.json 皆可撰寫,但意義不同。
套件端的 composer.json
應用程式端的 composer.json
build() 的實作,$ignore 陣列是將各套件的 configuration['dont-discover'] 以 array_merge 累積。因此技術上,套件本身也可以「停用自身相依套件的自動偵測」(例如:不希望內部使用的子套件的 Provider 重複註冊時)。但實務上較常使用的仍是應用程式端的停用。
於 dont-discover 指定 *
若 packagesToIgnore() 回傳的陣列中包含 *,則 $ignoreAll = true,會將所有套件的自動偵測整體停用。可用於 CI 或測試環境希望避免自動偵測的額外負擔,或希望於 bootstrap/providers.php 完全手動管理的情境。
快取檔案的實體
getCachedPackagesPath() 若有環境變數 APP_PACKAGES_CACHE 則回傳其值,否則回傳 bootstrap/cache/packages.php。
return 一個單純的關聯陣列。
php artisan package:discover 的輸出確認「偵測到哪些套件」。
快取被重建的時機
Illuminate\Foundation\ComposerScripts 掛勾 3 個 Composer 事件,皆呼叫相同的 clearCompiled()。
composer install / composer update / composer dump-autoload 任一者,設定快取、服務快取、套件快取都會一併被刪除。下次 Laravel 啟動時 PackageManifest::build() 便會執行,從 installed.json 的最新狀態重新建置。
這是標準 Laravel 專案於 composer.json 的 scripts 中所註冊的行為。
Laravel 應用程式的 composer.json(節錄)
以 php artisan package:discover 手動重建
當快取仍為舊資料,或未經 Composer 直接變更 vendor/ 的情況下,可透過 package:discover 指令手動重建。
$manifest->build() 並輸出結果,幾乎不含指令專屬邏輯。於 CI Pipeline 中使用 composer install --no-scripts 等 Composer 事件不會觸發的情況下,需明確呼叫此指令。
部署時的注意事項
正式部署時通常執行composer install --no-dev --optimize-autoloader,但若加上 --no-scripts,則套件快取不會被更新。建議於部署腳本中加入明確的重建步驟以保安全。
package:discover 需先於 config:cache 執行。若設定快取先被建立,後才加入的套件設定(如以 mergeConfigFrom 註冊的設定)可能無法反映。
總結
- 自動偵測並非依
composer.json的靜態內容,而是讀取 Composer 產生的vendor/composer/installed.json運作。 - 結果以純 PHP 陣列快取於
bootstrap/cache/packages.php,僅需require即可高速讀取。 - 快取於
composer install/update/dump-autoload各事件會自動被刪除,並於下次啟動時重新建置。 - 使用
--no-scripts執行 Composer 的環境中,需明確呼叫php artisan package:discover。 - 於
dont-discover指定*可整體停用自動偵測。
相關頁面
- 套件開發基礎 — 服務提供者與
extra.laravel的基本使用方式 - 延遲服務提供者 — 最佳化已偵測提供者的載入時機
- 以 Orchestra Testbench 進行套件測試 — Testbench 專屬的
package:discover指令