升级指南
升级指南
- 从 12.x 升级到 13.0
- 利用人工智能进行升级
高影响变更
- 更新依赖项
- 更新 Laravel 安装程序
- 请求伪造防护
中等影响变更
- 缓存 serializable_classes 配置项
- 在 MySQL 或 MariaDB 中使用数据库的 upsert 方法
低影响变更
- 缓存前缀与会话 Cookie 名称
- 集合模型序列化恢复预加载关联
- Container::call 与可空类默认值
- 域名路由注册优先级
- JobAttempted 事件异常负载
- 管理器的 extend 回调绑定
- 支持使用 JOIN、ORDER BY 和 LIMIT 执行 DELETE 操作
- 分页 Bootstrap 视图名称
- 多态中间表名称生成规则
- QueueBusy 事件属性重命名
- 测试中自动重置 Str Factories
从 12.x 升级到 13.0
预计升级时间:10 分钟
[!NOTE]
我们尝试记录每一个可能的重大变更。由于这些变更中的一些位于框架的偏僻部分,只有一部分变更可能实际影响您的应用程序。想节省时间吗?您可以使用 Laravel Shift 来帮助自动化您的应用程序升级。Shift 是一个由社区维护的服务,可以自动化完成 Laravel 的升级过程。
使用 AI 进行升级
您可以使用 Laravel Boost 来完成自动化升级。 Boost 是一个官方 MCP 服务器,旨在为您的 AI 助手提供引导式升级提示 —— 将它安装到任意 Laravel 12 应用后,在 Claude Code、Cursor、OpenCode、Gemini 或 VS Code 中使用 /upgrade-laravel-v13 命令,即可开始升级至 Laravel 13。该命令要求 Laravel Boost 版本为 ^2.0。
更新依赖项
影响可能性:高
您需要在应用的 composer.json 文件中更新以下依赖项:
laravel/framework更新至^13.0laravel/boost更新至^2.0laravel/tinker更新至^3.0phpunit/phpunit更新至^12.0pestphp/pest更新至^4.0
更新 Laravel 安装器
如果您正在使用 Laravel 安装器 CLI工具来创建新的 Laravel 应用,请更新您的安装器以兼容 Laravel 13.x。
如果您通过 composer global require 安装了 Laravel 安装器,可以使用 composer global update 进行更新:
composer global update laravel/installer
或者,如果您使用的是 Laravel Herd 附带的 Laravel 安装器,请将 Herd 更新至最新的版本。
缓存
缓存前缀与会话 Cookie 名称
影响可能性:低
Laravel 默认的缓存和 Redis 键前缀现在使用连字符后缀。
在大多数应用中,此更改不会生效,因为应用级配置文件已经定义了这些值。它主要影响那些在应用配置值缺失时依赖框架级回退配置的应用。
// Laravel <= 12.x
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_cache_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_database_';
Str::slug((string) env('APP_NAME', 'laravel'), '_').'_session';
// Laravel >= 13.x
Str::slug((string) env('APP_NAME', 'laravel')).'-cache-';
Str::slug((string) env('APP_NAME', 'laravel')).'-database-';
Str::slug((string) env('APP_NAME', 'laravel')).'-session';
要保留先前的行为,请在环境中显式配置 CACHE_PREFIX、REDIS_PREFIX 和 SESSION_COOKIE。
Store 和 Repository 契约:touch
影响可能性:极低
缓存契约现在包含一个用于延长项 TTL(生存时间)的 touch 方法。如果您维护了自定义的缓存存储实现,请添加此方法:
// Illuminate\Contracts\Cache\Store
public function touch($key, $seconds);
缓存 serializable_classes 配置
影响可能性:中等
默认应用的 cache 配置现在包含一个设置为 false 的 serializable_classes 选项。此配置增强了缓存反序列化行为的安全性,有助于在您的应用的 APP_KEY 泄露时防止 PHP 反序列化利用链攻击。如果您的应用有意在缓存中存储 PHP 对象,则应显式列出允许反序列化的类:
'serializable_classes' => [
App\Data\CachedDashboardStats::class,
App\Support\CachedPricingSnapshot::class,
],
如果您的应用之前依赖反序列化任意缓存对象,则需要将该用法迁移到显式的类允许列表或非对象缓存负载(例如数组)中。
容器
Container::call 和可为空类默认值
影响可能性:低
Container::call 现在在没有绑定时会尊重可为空的类参数默认值,这与 Laravel 12 中引入的构造函数注入行为一致:
$container->call(function (?Carbon $date = null) {
return $date;
});
// Laravel <= 12.x: Carbon 实例
// Laravel >= 13.x: null
如果你的方法调用注入逻辑依赖于先前行为,则可能需要更新它。
契约
Dispatcher 契约:dispatchAfterResponse
影响可能性:极低
Illuminate\Contracts\Bus\Dispatcher 契约现在包含了 dispatchAfterResponse($command, $handler = null) 方法。
如果您维护了自定义的调度器,请将此方法添加到您的类中。
ResponseFactory 契约:eventStream
影响可能性:极低
Illuminate\Contracts\Routing\ResponseFactory 契约现在包含了一个 eventStream 方法签名。
如果您维护了该契约的自定义实现,应添加此方法。
MustVerifyEmail 契约:markEmailAsUnverified
影响可能性:极低
Illuminate\Contracts\Auth\MustVerifyEmail 契约现在包含 markEmailAsUnverified() 方法。
如果您提供了该契约的自定义实现,请添加此方法以保持兼容性。
数据库
使用 MySQL 或 MariaDB 进行数据库 upsert 操作
影响可能性:中等
Laravel 现在会验证调用方是否提供了非空的 uniqueBy 值,并在值为空时抛出 InvalidArgumentException,而不是生成无效的 SQL 语句。
尽管 MariaDB 和 MySQL 数据库驱动会忽略 uniqueBy 值并始终使用表的主键和唯一索引来检测已存在的记录,但验证规则依然适用。如果 uniqueBy 为空,将抛出 InvalidArgumentException。
带有 JOIN、ORDER BY 和 LIMIT 的 MySQL DELETE 查询
影响可能性:低
Laravel 现在会在 MySQL 语法中完整编译包含 ORDER BY 和 LIMIT 的 DELETE ... JOIN 查询。
在之前的版本中,对于带连接的删除操作,ORDER BY / LIMIT 子句可能会被静默忽略。在 Laravel 13 中,这些子句会被包含在生成的 SQL 中。因此,不支持该语法的数据库引擎(如标准 MySQL / MariaDB 变体)现在可能会抛出 QueryException,而不是执行无限制的删除。
Eloquent
模型启动与嵌套实例化
影响可能性:极低
现在,在模型仍在启动过程中创建新的模型实例将被禁止,并会抛出 LogicException。
这会影响在模型 boot 方法或 trait boot* 方法中实例化模型的代码:
protected static function boot()
{
parent::boot();
// 启动期间不再允许这样做...
(new static())->getTable();
}
请将这类逻辑移出启动周期,以避免嵌套启动。
多态中间表名称生成
影响可能性:低
当使用自定义的中间模型类为多态中间模型推断表名时,Laravel 现在会生成复数形式的表名。
如果您的应用依赖于之前多态中间表推断出的单数表名,并且使用了自定义的中间类,您应在中间模型中显式定义表名。
集合模型序列化恢复预加载关联
影响可能性:低
当 Eloquent 模型集合被序列化并恢复时(例如在队列任务中),集合中模型的预加载关联现在也会被恢复。
如果您的代码依赖于反序列化后关联关系不存在的行为,您可能需要调整相关逻辑。
HTTP 客户端
HTTP 客户端 Response::throw 与 throwIf 方法签名
影响可能性:极低
HTTP 客户端响应的方法现在在方法签名中声明了其回调参数:
public function throw($callback = null);
public function throwIf($condition, $callback = null);
如果您在自定义响应类中重写了这些方法,请确保您的方法签名与其保持兼容。
通知
默认密码重置邮件主题
影响可能性:极低
Laravel 的默认密码重置邮件主题已更改:
// Laravel <= 12.x
重置密码通知
// Laravel >= 13.x
重置您的密码
如果您的测试、断言或翻译覆盖依赖于之前的默认字符串,请相应更新它们。
队列通知与缺失模型
影响可能性:极低
队列通知现在会尊重通知类上定义的 #[DeleteWhenMissingModels] 属性和 $deleteWhenMissingModels 属性。
在先前版本中,在你期望它们被删除的情况下,缺失模型仍可能导致队列通知任务失败。
队列
JobAttempted 事件异常负载
影响可能性:低
Illuminate\Queue\Events\JobAttempted 事件现在通过 $exception 属性公开异常对象(或 null),取代了之前的布尔类型 $exceptionOccurred 属性:
// Laravel <= 12.x
$event->exceptionOccurred;
// Laravel >= 13.x
$event->exception;
如果您监听此事件,请相应更新您的监听器代码。
QueueBusy 事件属性重命名
影响可能性:低
Illuminate\Queue\Events\QueueBusy 事件的 $connection 属性已重命名为 $connectionName,以与其他队列事件保持一致。
如果您的监听器引用了 $connection,请将其更新为 $connectionName。
Queue 契约方法添加
影响可能性:极低
Illuminate\Contracts\Queue\Queue 契约现在包含了之前在文档块(docblock)中声明的队列大小检查方法。
如果您维护了该契约的自定义队列驱动实现,请为以下方法添加实现:
pendingSizedelayedSizereservedSizecreationTimeOfOldestPendingJob
路由
域名路由注册优先级
影响可能性:低
带有显式域名的路由现在在路由匹配中优先于非域名路由。
这使得即使非域名路由更早注册,通配子域名路由能够保持一致的行为。如果您的应用依赖于域名路由与非域名路由之间原有的注册优先级,请检查路由匹配行为。
任务调度
withScheduling 注册时机
影响可能性:极低
通过 ApplicationBuilder::withScheduling() 注册的调度任务现在会延迟到 Schedule 被解析时才执行。
如果您的应用依赖于在引导阶段立即执行调度注册,您可能需要调整相关逻辑。
安全
请求伪造保护
影响可能性:高
Laravel 的 CSRF 中间件已从 VerifyCsrfToken 重命名为 PreventRequestForgery,并且现在包含使用 Sec-Fetch-Site 标头进行的请求来源验证。
VerifyCsrfToken 和 ValidateCsrfToken 仍作为已弃用的别名保留,但直接的引用应更新为 PreventRequestForgery,特别是在测试或路由定义中排除中间件时:
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
// Laravel <= 12.x
->withoutMiddleware([VerifyCsrfToken::class]);
// Laravel >= 13.x
->withoutMiddleware([PreventRequestForgery::class]);
中间件配置 API 现在也提供了 preventRequestForgery(...) 方法。
支持
管理器 extend 回调绑定
影响可能性:低
通过管理器 extend 方法注册的自定义驱动闭包现在会绑定到管理器实例。
如果您之前在这些回调中依赖于另一个绑定对象(例如服务提供者实例)作为这些回调中的 $this,您应将这些值通过 use (...) 语法捕获到闭包中。
测试间重置 Str 工厂
影响可能性:低
Laravel 现在在测试拆卸(teardown)时会重置自定义的 Str 工厂。
如果您的测试依赖于自定义的 UUID / ULID / 随机字符串工厂在测试方法之间保持持久化,您应在每个相关测试或设置钩子中重新设置它们。
Js::from 默认使用未转义的 Unicode
影响可能性:极低
Illuminate\Support\Js::from 现在默认使用 JSON_UNESCAPED_UNICODE 选项。
如果您的测试或前端输出比较依赖于已转义的 Unicode 序列(例如 \u00e8),请更新您的预期值。
工具类
Symfony PHP 8.5 Polyfill 与全局函数冲突
影响可能性:低
Laravel 13 引入了对 symfony/polyfill-php85 的依赖。在低于 PHP 8.5 的版本上,此 Polyfill 会定义诸如 array_first() 和 array_last() 等全局函数——除非这些函数已经在引导过程中更早地定义过。
这些函数可能与传统的辅助函数包(如 laravel/helpers)或使用相同名称的自定义全局辅助函数产生冲突。例如,历史版本的 array_first() 辅助函数接受一个回调以返回第一个匹配的元素,而 Polyfill 版本仅返回数组的第一个元素。
为避免冲突并确保在不同 PHP 版本间行为一致,您应优先使用 Illuminate\Support\Arr 方法:
use Illuminate\Support\Arr;
Arr::first($array, function ($value) {
return /* 条件 */;
});
视图
分页 Bootstrap 视图名称
影响可能性:低
Bootstrap 3 默认的内部分页视图名称现在已明确:
// Laravel <= 12.x
pagination::default
pagination::simple-default
// Laravel >= 13.x
pagination::bootstrap-3
pagination::simple-bootstrap-3
如果您的应用直接引用了旧的分页视图名称,请更新这些引用。
其他事项
我们还建议您查看 laravel/laravel 的 GitHub 仓库 中的变更。虽然许多更改并非必须,但您可能希望将这些文件与您的应用保持同步。其中一些更改已在本升级指南中涵盖,而其他更改(例如配置文件或注释的更新)则未提及。您可以使用 GitHub 比较工具 轻松查看变更,并选择对您重要的更新。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
Laravel 13 中文文档
关于 LearnKu
推荐文章: