前言
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
影响度:中
BelongsToMany的firstOrNew/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 的地方需要检查。
驱动依赖
从 withSwiftMessage 到 withSymfonyMessage
Illuminate\Mail\Mailer 的 send、html、raw、plain 现在返回 Illuminate\Mail\SentMessage 而不是 void。MessageSent 事件的 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 选项。
Storage::extend() 的回调改为直接返回 Illuminate\Filesystem\FilesystemAdapter。
BelongsToMany 的 firstOrNew / 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 的核心类并覆写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。先检查邮件发送、存储、Custom Cast、测试辅助器,能减少升级后的问题。| 变更点 | 影响度 | 应对 |
|---|---|---|
PHP 8.0.2 / laravel/framework:^9.0 | 高 | 更新 composer.json 与运行环境 |
| 迁移到 Symfony Mailer | 高 | 检查 SwiftMailer 相关 API 与 mail 配置 |
| Flysystem 3.x | 高 | 检查 Storage 的返回值、异常与驱动依赖 |
BelongsToMany 的 upsert 系方法 | 中 | 注意查询对象已变为关联模型的表 |
Custom Cast 与 null | 中 | 修复 set() 收到 null 时会崩的地方 |
| HTTP Client 30 秒超时 | 中 | 只对必要请求显式设置 timeout() |
废弃 assertDeleted | 中 | 替换为 assertModelMissing() |
lang 目录移动 | 中 | 固定路径引用改用 app()->langPath() |
password 规则变更 | 中 | 改成 current_password |
| 排除未校验数组键 | 中 | 只在需要时使用 includeUnvalidatedArrayKeys() |