前言
Laravel 9 於 2022 年 2 月 8 日發佈。本指南整理從 Laravel 8.x 升級到 9.x 的步驟與影響較大的變更點。升級預估所需時間約為 30 分鐘。不過因為郵件寄送、檔案儲存、自訂 cast、以及框架核心類別的覆寫狀況,工作量可能會增加。
使用 Laravel Shift 自動化升級
也可以使用 Laravel Shift 自動化升級。Shift 會協助更新composer.json 與設定檔,作為差異確認的起點很方便。
依影響程度分類的變更
影響程度:高
- 更新依賴套件
- 遷移到 Flysystem 3.x
- 遷移到 Symfony Mailer
影響程度:中
BelongsToMany的firstOrNew/firstOrCreate/updateOrCreate方法- Custom Cast 與
null的行為 - HTTP client 的預設 timeout
- PHP Return Types 的新增
- Postgres 的
schema設定名稱變更 - 廢除
assertDeleted方法 lang目錄的搬移- 密碼規則的變更
when/unless方法的變更- validation 中未驗證陣列 key 的處理
升級步驟
更新依賴套件
影響程度:高 Laravel 9 需要 PHP 8.0.2 以上。首先請重新檢視composer.json 的依賴。
- 移除
facade/ignition,改用spatie/laravel-ignition:^1.0 - 若使用
pusher/pusher-php-server,請更新到^5.0 - 確認使用中的第三方套件是否有 Laravel 9 相容版本
- 若使用 Vonage 通知 channel,也請確認個別的升級指南
PHP 版本需求
影響程度:高 Laravel 9 必須使用 PHP 8.0.2 以上。請在 CI、本機開發環境、正式環境的 PHP 版本都對齊後再進行升級。遷移到 Symfony Mailer
影響程度:高 Laravel 9 的一大變更之一是從 2021 年 12 月結束維護的 SwiftMailer 遷移到 Symfony Mailer。僅使用一般Mail::to()->send() 的應用影響較小,但若直接使用 SwiftMailer 的低階 API,就需要確認。
Driver 依賴套件
從 withSwiftMessage 到 withSymfonyMessage
Illuminate\Mail\Mailer 的 send、html、raw、plain 現在會回傳 Illuminate\Mail\SentMessage 而不是 void。另外 MessageSent 事件的 message 屬性中,現在會是 Symfony\Component\Mime\Email 而非 Swift_Message。
重新檢視 SMTP 設定
Symfony Mailer 中 SMTP 的stream 選項已廢除,支援的設定移到最上層。
auth_mode 也不再需要明確設定。將營運方式改為在送出前驗證電子郵件地址,會比事後回收無效地址更安全。
遷移到 Flysystem 3.x
影響程度:高 Laravel 9 將Storage facade 的內部實作從 Flysystem 1.x 更新到 3.x。檔案操作方法盡可能保持相容,但在例外、回傳值、adapter 註冊等部分有差異。
追加安裝 Driver
Storage 主要行為變更
put/write/writeStream預設會覆寫既有檔案- 寫入失敗時回傳
false而非例外 - 讀取不存在的檔案時回傳
null而非例外 - 刪除不存在的檔案時
delete回傳true - cached adapter 已被移除,可移除
disk設定中的cachekey
throw 選項。
Storage::extend() 的 callback 直接回傳 Illuminate\Filesystem\FilesystemAdapter。
BelongsToMany 的 firstOrNew / firstOrCreate / updateOrCreate
影響程度:中
Laravel 8 中傳給這些方法的第 1 個引數屬性陣列是與中間表比對。Laravel 9 則是與關聯 model 的資料表比對。
firstOrCreate 開始可接收第 2 引數 $values,行為與其他 relation 對齊。
Custom Cast 與 null
影響程度:中
Laravel 9 中,即使對 cast 對象指派 null,也會呼叫 custom cast 的 set 方法。未預期收到 null 的 cast,升級後可能會拋出例外。
HTTP client 的預設 timeout
影響程度:中 HTTP client 的預設 timeout 改為 30 秒。以前可能會無限等待。PHP Return Types 的新增
影響程度:中 Laravel 9 中,為配合 PHP 本體或 Symfony 的需求,各種核心類別已加上回傳型別。若你繼承 Laravel 的核心類別並覆寫offsetGet、offsetSet、jsonSerialize、open、read 等方法,也請在自己的實作加上相同的回傳型別。
Postgres 的 schema 設定名稱變更
影響程度:中
若在 Postgres 連線設定 search path,請將 config/database.php 的 key 名稱從 schema 改為 search_path。
從 assertDeleted 到 assertModelMissing
影響程度:中
用於確認 model 刪除的 assertDeleted 請替換為 assertModelMissing。
lang 目錄的搬移
影響程度:中
新的 Laravel 9 應用中,語言檔案的放置位置從 resources/lang 改為專案根目錄的 lang。若只是直接執行既有應用影響不大,但若要對齊新的 skeleton,或套件公開翻譯檔案時請重新檢視。
密碼規則的變更
影響程度:中 驗證目前登入使用者的密碼是否相符的password rule 已重新命名為 current_password。
when / unless 方法的變更
影響程度:中
Laravel 8 中將 closure 傳給 when 或 unless 時,該 closure 本身會被評估為 truthy,可能導致意外的條件分支執行。Laravel 9 中會執行 closure,並將其回傳值作為條件使用。
未驗證陣列 key 的處理
影響程度:中 Laravel 9 中,validated() 回傳的陣列總是會排除未驗證的陣列 key。若要維持 Laravel 8 的相容行為,只在必要時明確呼叫 includeUnvalidatedArrayKeys()。