メインコンテンツへスキップ

はじめに

Laravel 9 は 2022年2月8日にリリースされました。このガイドでは Laravel 8.x から 9.x へのアップグレード手順と、影響が大きい変更点を整理します。
アップグレードに必要な推定時間は 約30分 です。ただし、メール送信・ファイルストレージ・独自キャスト・フレームワークのコアクラスのオーバーライド状況によって作業量は増える場合があります。

Laravel Shift を使った自動アップグレード

Laravel Shift を使ってアップグレードを自動化することもできます。Shift は composer.json や設定ファイルの更新を補助してくれるため、差分確認の出発点として便利です。

影響度別の変更点

影響度: 高

  • 依存関係の更新
  • Flysystem 3.x への移行
  • Symfony Mailer への移行

影響度: 中

  • BelongsToManyfirstOrNew / 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\Mailersendhtmlrawplainvoid ではなく 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 を返す
  • 存在しないファイルの deletetrue を返す
  • cached adapter は削除されたため、disk 設定内の cache キーを削除できる
以前のように書き込み失敗時に例外を使いたい場合は、throw オプションを設定してください。
独自の filesystem ドライバーを登録している場合は、Storage::extend() のコールバックが Illuminate\Filesystem\FilesystemAdapter を直接返す実装へ調整してください。

BelongsToManyfirstOrNew / 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 のコアクラスを継承して offsetGetoffsetSetjsonSerializeopenread などをオーバーライドしている場合は、自前の実装にも同じ戻り値型を追加してください。

Postgres の schema 設定名変更

影響度: 中 Postgres 接続で検索パスを設定している場合、config/database.php のキー名を schema から search_path へ変更してください。

assertDeleted から assertModelMissing

影響度: 中 モデルの削除確認に使っていた assertDeletedassertModelMissing へ置き換えてください。

lang ディレクトリの移動

影響度: 中 新規 Laravel 9 アプリケーションでは、言語ファイルの配置先が resources/lang ではなくプロジェクトルートの lang になりました。既存アプリをそのまま動かすだけなら大きな影響は少ないですが、新しいスケルトンへ寄せる場合やパッケージで翻訳ファイルを公開している場合は見直してください。

パスワードルールの変更

影響度: 中 現在ログイン中ユーザーのパスワードと一致することを検証する password ルールは、current_password にリネームされました。

when / unless メソッドの変更

影響度: 中 Laravel 8 では、whenunless にクロージャを渡すと、そのクロージャ自体が 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.0composer.json と実行環境を更新
Symfony Mailer への移行SwiftMailer 系 API と mail 設定を確認
Flysystem 3.xStorage の戻り値・例外・ドライバー依存関係を確認
BelongsToMany の upsert 系メソッド検索対象が関連モデルのテーブルになった点を確認
Custom Casts と nullset()null を受けても壊れないよう修正
HTTP クライアントの 30 秒タイムアウト必要なリクエストだけ timeout() を明示
assertDeleted 廃止assertModelMissing() に置き換え
lang ディレクトリ移動固定パス参照を app()->langPath() に変更
password ルール変更current_password へ更新
未検証配列キーの除外必要時のみ includeUnvalidatedArrayKeys() を利用

参考資料

最終更新日 2026年6月4日