升级指南
高影响变化
中等影响变化
低影响变化
从 12.x 升级到 13.0
预计升级时间:10 分钟
NOTE
我们尝试记录每一个可能的破坏性变更。由于其中一些破坏性变更位于框架的冷门部分,因此实际上可能只有部分变更会影响您的应用程序。为了节省时间,您可以使用 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 键前缀现在使用连字符后缀。此外,默认会话 Cookie 名称现在对应用程序名称使用 Str::snake(...)。
在大多数应用程序中,此更改不会产生影响,因为应用程序级别的配置文件已定义这些值。这主要影响当相应应用程序配置值不存在时依赖框架级回退配置的应用程序。
如果你的应用程序依赖这些生成的默认值,升级后缓存键和会话 Cookie 名称可能会更改:
// 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::snake((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。
MySQL 带有 JOIN、ORDER BY 和 LIMIT 的 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 契约现在包含先前仅在文档块中声明的队列大小检查方法。
如果你维护此契约的自定义队列驱动实现,请为以下方法添加实现:
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 现在在测试拆卸期间重置自定义 Str 工厂。
如果你的测试依赖于在测试方法之间持续存在的自定义 UUID/ULID/随机字符串工厂,则应在每个相关测试或设置钩子中设置它们。
Js::from 默认使用未转义的 Unicode
影响可能性:极低
Illuminate\Support\Js::from 现在默认使用 JSON_UNESCAPED_UNICODE。
如果你的测试或前端输出比较依赖于转义的 Unicode 序列(例如 \u00e8),请更新你的期望。
视图
分页 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 比较工具 轻松查看更改,并选择哪些更新对你重要。