跳转到主要内容

前言

Laravel 9 于 2022 年 2 月 8 日发布。本文整理从 Laravel 8.x 升级到 9.x 的步骤,以及影响面较大的变更点。
预计升级时间约 30 分钟。如果你自定义了邮件发送、文件存储、Custom Cast,或者覆写了框架的核心类,工作量可能更多。

用 Laravel Shift 自动升级

也可以用 Laravel Shift 自动化升级。Shift 会协助更新 composer.json 和配置文件,可以作为你审阅 diff 的起点。

按影响面分级的变更

影响度:高

  • 依赖更新
  • 迁移到 Flysystem 3.x
  • 迁移到 Symfony Mailer

影响度:中

  • BelongsToManyfirstOrNew / firstOrCreate / updateOrCreate
  • Custom Cast 与 null 的行为
  • HTTP Client 的默认超时
  • 新增 PHP Return Type
  • 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 的地方需要检查。

驱动依赖

withSwiftMessagewithSymfonyMessage

Illuminate\Mail\Mailersendhtmlrawplain 现在返回 Illuminate\Mail\SentMessage 而不是 voidMessageSent 事件的 message 属性也从 Swift_Message 变成了 Symfony\Component\Mime\Email

重新检查 SMTP 配置

Symfony Mailer 废弃了 SMTP 的 stream 选项,支持的配置项被移到顶层。
不再需要显式设置 auth_mode。相较发送后再回收无效邮件地址,推荐在发送前完成校验。

迁移到 Flysystem 3.x

影响度:高 Laravel 9 把 Storage facade 内部实现从 Flysystem 1.x 升到了 3.x。文件操作方法尽量保持了兼容,但异常、返回值、适配器注册周围有差异。

需要额外安装的驱动

Storage 的主要行为变化

  • put / write / writeStream 默认会覆盖已有文件
  • 写入失败时返回 false 而不是抛异常
  • 读取不存在的文件返回 null 而不是异常
  • 对不存在文件调用 delete 会返回 true
  • cached adapter 已被移除,可以从 disk 配置中删除 cache
如果想像以前那样在写入失败时抛异常,请设置 throw 选项。
如果注册了自定义 filesystem 驱动,请把 Storage::extend() 的回调改为直接返回 Illuminate\Filesystem\FilesystemAdapter

BelongsToManyfirstOrNew / firstOrCreate / updateOrCreate

影响度:中 在 Laravel 8 中,这些方法的第一个参数(属性数组)是和中间表比较的。Laravel 9 改为和关联模型的表比较。
同时,firstOrCreate 也支持第二个参数 $values,与其他关联的行为对齐。

Custom Cast 与 null

影响度:中 Laravel 9 中,即便把 null 赋给要 cast 的字段,custom cast 的 set 方法也会被调用。没有考虑 null 的 cast 升级后可能抛异常。

HTTP Client 的默认超时

影响度:中 HTTP Client 的默认超时变为 30 秒。以前有可能无限等待。

新增 PHP Return Type

影响度:中 为了对齐 PHP 本身和 Symfony 的要求,Laravel 9 给各个核心类加上了返回值类型。如果你继承了 Laravel 的核心类并覆写 offsetGetoffsetSetjsonSerializeopenread 等,请给自己的实现也加上同样的返回值类型。

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 中,给 whenunless 传闭包时,闭包本身会被当作 truthy,可能触发非预期分支。Laravel 9 中会执行闭包,并把返回值作为条件。

未校验数组键的处理

影响度:中 Laravel 9 中,validated() 返回的数组会始终排除未校验的数组键。想保留 Laravel 8 的兼容行为时,请显式调用 includeUnvalidatedArrayKeys()

总结

Laravel 8 到 9 的升级重点是:升到 PHP 8.0.2、迁移到 Symfony Mailer、适配 Flysystem 3.x。先检查邮件发送、存储、Custom Cast、测试辅助器,能减少升级后的问题。

参考资料

最后修改于 2026年7月18日