はじめに
Laravel 9 は 2022年2月8日にリリースされました。このガイドでは Laravel 8.x から 9.x へのアップグレード手順と、影響が大きい変更点を整理します。アップグレードに必要な推定時間は 約30分 です。ただし、メール送信・ファイルストレージ・独自キャスト・フレームワークのコアクラスのオーバーライド状況によって作業量は増える場合があります。
Laravel Shift を使った自動アップグレード
Laravel Shift を使ってアップグレードを自動化することもできます。Shift はcomposer.json や設定ファイルの更新を補助してくれるため、差分確認の出発点として便利です。
影響度別の変更点
影響度: 高
- 依存関係の更新
- Flysystem 3.x への移行
- Symfony Mailer への移行
影響度: 中
BelongsToManyのfirstOrNew/firstOrCreate/updateOrCreateメソッド- Custom Casts と
nullの挙動 - HTTP クライアントのデフォルトタイムアウト
- PHP Return Types の追加
- Postgres の
schema設定名変更 assertDeletedメソッドの廃止langディレクトリの移動- パスワードルールの変更
when/unlessメソッドの変更- バリデーションでの未検証配列キーの扱い
アップグレード手順
依存関係の更新
影響度: 高 Laravel 9 では PHP 8.0.2 以上 が必要です。まずcomposer.json の依存関係を見直してください。
facade/ignitionを削除し、spatie/laravel-ignition:^1.0に置き換えるpusher/pusher-php-serverを使っている場合は^5.0へ更新する- 利用中のサードパーティパッケージが Laravel 9 対応版か確認する
- Vonage 通知チャンネルを使っている場合は個別のアップグレードガイドも確認する
PHPバージョン要件
影響度: 高 Laravel 9 では PHP 8.0.2 以上が必須です。CI、ローカル開発環境、本番環境のすべてで PHP バージョンをそろえてからアップグレードを進めてください。Symfony Mailer への移行
影響度: 高 Laravel 9 の大きな変更のひとつは、2021年12月でメンテナンス終了となった SwiftMailer から Symfony Mailer への移行です。通常のMail::to()->send() だけを使っているアプリケーションは影響が少ない一方で、SwiftMailer の低レベル API を直接触っている場合は確認が必要です。
ドライバー依存関係
withSwiftMessage から withSymfonyMessage へ
Illuminate\Mail\Mailer の send、html、raw、plain は void ではなく Illuminate\Mail\SentMessage を返すようになりました。また、MessageSent イベントの message プロパティには Swift_Message ではなく Symfony\Component\Mime\Email が入ります。
SMTP 設定の見直し
Symfony Mailer では SMTP のstream オプションが廃止され、サポートされる設定はトップレベルに移動します。
auth_mode の明示設定も不要になりました。無効なメールアドレスを送信後に回収するのではなく、送信前にバリデーションする運用へ寄せるのが安全です。
Flysystem 3.x への移行
影響度: 高 Laravel 9 はStorage ファサードの内部実装を Flysystem 1.x から 3.x へ更新しました。ファイル操作メソッドはできるだけ互換性を保っていますが、例外・戻り値・アダプター登録周りに差分があります。
ドライバーの追加インストール
Storage の主な挙動変更
put/write/writeStreamは既存ファイルをデフォルトで上書きする- 書き込み失敗時は例外ではなく
falseを返す - 存在しないファイルの読み込みは例外ではなく
nullを返す - 存在しないファイルの
deleteはtrueを返す - cached adapter は削除されたため、
disk設定内のcacheキーを削除できる
throw オプションを設定してください。
Storage::extend() のコールバックが Illuminate\Filesystem\FilesystemAdapter を直接返す実装へ調整してください。
BelongsToMany の firstOrNew / firstOrCreate / updateOrCreate
影響度: 中
Laravel 8 では、これらのメソッドに渡した第1引数の属性配列が中間テーブルと比較されていました。Laravel 9 では、関連モデルのテーブルと比較されます。
firstOrCreate は第2引数の $values を受け取れるようになり、他のリレーションと挙動がそろいました。
Custom Casts と null
影響度: 中
Laravel 9 では、キャスト対象に null を代入した場合でも custom cast の set メソッドが呼ばれます。null を想定していない cast はアップグレード後に例外を出す可能性があります。
HTTP クライアントのデフォルトタイムアウト
影響度: 中 HTTP クライアントのデフォルトタイムアウトは 30 秒になりました。以前は無制限で待ち続けることがありました。PHP Return Types の追加
影響度: 中 Laravel 9 では、PHP 本体や Symfony の要件に合わせて各種コアクラスへ戻り値型が追加されました。Laravel のコアクラスを継承してoffsetGet、offsetSet、jsonSerialize、open、read などをオーバーライドしている場合は、自前の実装にも同じ戻り値型を追加してください。
Postgres の schema 設定名変更
影響度: 中
Postgres 接続で検索パスを設定している場合、config/database.php のキー名を schema から search_path へ変更してください。
assertDeleted から assertModelMissing へ
影響度: 中
モデルの削除確認に使っていた assertDeleted は assertModelMissing へ置き換えてください。
lang ディレクトリの移動
影響度: 中
新規 Laravel 9 アプリケーションでは、言語ファイルの配置先が resources/lang ではなくプロジェクトルートの lang になりました。既存アプリをそのまま動かすだけなら大きな影響は少ないですが、新しいスケルトンへ寄せる場合やパッケージで翻訳ファイルを公開している場合は見直してください。
パスワードルールの変更
影響度: 中 現在ログイン中ユーザーのパスワードと一致することを検証するpassword ルールは、current_password にリネームされました。
when / unless メソッドの変更
影響度: 中
Laravel 8 では、when や unless にクロージャを渡すと、そのクロージャ自体が truthy と評価されるため意図せず条件分岐が実行されることがありました。Laravel 9 ではクロージャが実行され、その戻り値が条件として使われます。
未検証配列キーの扱い
影響度: 中 Laravel 9 では、validated() が返す配列から未検証の配列キーが常に除外されます。Laravel 8 の互換挙動を維持したい場合だけ、includeUnvalidatedArrayKeys() を明示的に呼び出してください。
まとめ
Laravel 8 から 9 へのアップグレードでは、PHP 8.0.2 への更新、Symfony Mailer への移行、Flysystem 3.x への対応が中心です。メール送信・ストレージ・独自キャスト・テストヘルパーを先に点検すると、アップグレード後の不具合を減らせます。| 変更点 | 影響度 | 対応 |
|---|---|---|
PHP 8.0.2 / laravel/framework:^9.0 | 高 | composer.json と実行環境を更新 |
| Symfony Mailer への移行 | 高 | SwiftMailer 系 API と mail 設定を確認 |
| Flysystem 3.x | 高 | Storage の戻り値・例外・ドライバー依存関係を確認 |
BelongsToMany の upsert 系メソッド | 中 | 検索対象が関連モデルのテーブルになった点を確認 |
Custom Casts と null | 中 | set() が null を受けても壊れないよう修正 |
| HTTP クライアントの 30 秒タイムアウト | 中 | 必要なリクエストだけ timeout() を明示 |
assertDeleted 廃止 | 中 | assertModelMissing() に置き換え |
lang ディレクトリ移動 | 中 | 固定パス参照を app()->langPath() に変更 |
password ルール変更 | 中 | current_password へ更新 |
| 未検証配列キーの除外 | 中 | 必要時のみ includeUnvalidatedArrayKeys() を利用 |