Skip to content

升级指南

高影响变更

中影响变更

低影响变更

从 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-13 斜杠命令即可开始升级到 Laravel 13。

更新依赖

影响可能性:高

你需要在应用的 composer.json 文件中更新以下依赖:

  • laravel/framework 升级到 ^13.0
  • laravel/tinker 升级到 ^3.0
  • phpunit/phpunit 升级到 ^12.0
  • pestphp/pest 升级到 ^4.0

更新 Laravel 安装器

如果你使用 Laravel 安装器 CLI 工具创建新的 Laravel 应用,应更新安装器以兼容 Laravel 13.x。

如果你通过 composer global require 安装了 Laravel 安装器,可以使用 composer global update 进行更新:

shell
composer global update laravel/installer

或者,如果你使用的是 Laravel Herd 内置的 Laravel 安装器,应将 Herd 更新到最新版本。

Cache

影响可能性:低

Laravel 默认的 cache 和 Redis key 前缀现在使用连字符后缀。此外,默认的 session cookie 名称现在对应用名称使用 Str::snake(...)

大多数应用不受此变更影响,因为应用级配置文件已显式定义了这些值。此变更主要影响依赖框架级回退配置(即对应应用配置值不存在时)的应用。

如果你的应用依赖这些自动生成的默认值,升级后 cache key 和 session cookie 名称可能会发生变化:

php
// 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_PREFIXREDIS_PREFIXSESSION_COOKIE

StoreRepository Contracts:touch

影响可能性:极低

cache contracts 现在包含用于延长条目 TTL 的 touch 方法。如果你维护自定义 cache store 实现,应添加此方法:

php
// Illuminate\Contracts\Cache\Store
public function touch($key, $seconds);

Cache serializable_classes 配置

影响可能性:中

默认应用 cache 配置现在包含一个设置为 falseserializable_classes 选项。这强化了 cache 反序列化行为,在你的应用 APP_KEY 泄露时有助于防止 PHP 反序列化 gadget 链攻击。如果你的应用有意在 cache 中存储 PHP 对象,应显式列出允许反序列化的类:

php
'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
],

如果你的应用之前依赖于对任意缓存对象进行反序列化,需要将该用法迁移到显式类白名单,或改用非对象的 cache 载荷(如数组)。

Container

Container::call 与可空类默认值

影响可能性:低

Container::call 现在在没有绑定时遵循可空类参数默认值,与 Laravel 12 引入的构造函数注入行为一致:

php
$container->call(function (?Carbon $date = null) {
    return $date;
});

// Laravel <= 12.x: Carbon 实例
// Laravel >= 13.x: null

如果你的方法调用注入逻辑依赖于之前的行为,可能需要进行更新。

Contracts

Dispatcher Contract:dispatchAfterResponse

影响可能性:极低

Illuminate\Contracts\Bus\Dispatcher contract 现在包含 dispatchAfterResponse($command, $handler = null) 方法。

如果你维护自定义 dispatcher 实现,请在你的类中添加此方法。

ResponseFactory Contract:eventStream

影响可能性:极低

Illuminate\Contracts\Routing\ResponseFactory contract 现在包含 eventStream 签名。

如果你维护该 contract 的自定义实现,应添加此方法。

MustVerifyEmail Contract:markEmailAsUnverified

影响可能性:极低

Illuminate\Contracts\Auth\MustVerifyEmail contract 现在包含 markEmailAsUnverified()

如果你提供了该 contract 的自定义实现,请添加此方法以保持兼容性。

数据库

MySQL DELETE 查询与 JOINORDER BYLIMIT

影响可能性:低

Laravel 现在为 MySQL 语法编译完整的 DELETE ... JOIN 查询,包括 ORDER BYLIMIT

在之前的版本中,带 JOIN 的删除操作中 ORDER BY / LIMIT 子句可能被静默忽略。在 Laravel 13 中,这些子句会包含在生成的 SQL 中。因此,不支持此语法的数据库引擎(如标准 MySQL / MariaDB 变体)现在可能会抛出 QueryException,而不是执行无限制的删除。

Eloquent

模型启动与嵌套实例化

影响可能性:极低

在模型仍在启动时创建新的模型实例现在是不允许的,会抛出 LogicException

这影响在模型 boot 方法或 trait boot* 方法内部实例化模型的代码:

php
protected static function boot()
{
    parent::boot();

    // 启动期间不再允许...
    (new static())->getTable();
}

请将此逻辑移到 boot 周期之外以避免嵌套启动。

多态中间表名生成

影响可能性:低

当使用自定义中间模型类推断多态中间表的表名时,Laravel 现在生成复数形式名称。

如果你的应用依赖之前为 morph 中间表推断的单数名称并使用了自定义中间类,应在中间模型上显式定义表名。

集合模型序列化恢复预加载关联

影响可能性:低

当 Eloquent 模型集合被序列化并还原时(例如在队列 job 中),集合模型的预加载关联现在会被还原。

如果你的代码依赖于反序列化后关联不存在的行为,可能需要调整该逻辑。

HTTP 客户端

HTTP 客户端 Response::throwthrowIf 签名

影响可能性:极低

HTTP 客户端响应方法现在在方法签名中声明其回调参数:

php
public function throw($callback = null);
public function throwIf($condition, $callback = null);

如果你在自定义响应类中覆盖了这些方法,请确保方法签名兼容。

通知

默认密码重置邮件主题

影响可能性:极低

Laravel 默认的密码重置邮件主题已更改:

text
// Laravel <= 12.x
Reset Password Notification

// Laravel >= 13.x
Reset your password

如果你的测试、断言或翻译覆盖依赖于之前的默认字符串,请相应更新。

队列通知与缺失模型

影响可能性:极低

队列通知现在遵循通知类上定义的 #[DeleteWhenMissingModels] attribute 和 $deleteWhenMissingModels 属性。

在之前的版本中,缺失的模型在你预期通知 job 被删除的情况下仍可能导致 job 失败。

队列

JobAttempted 事件异常载荷

影响可能性:低

Illuminate\Queue\Events\JobAttempted 事件现在通过 $exception 暴露异常对象(或 null),替换了之前的布尔值 $exceptionOccurred 属性:

php
// Laravel <= 12.x
$event->exceptionOccurred;

// Laravel >= 13.x
$event->exception;

如果你监听此事件,请相应更新你的监听器代码。

QueueBusy 事件属性重命名

影响可能性:低

Illuminate\Queue\Events\QueueBusy 事件的 $connection 属性已重命名为 $connectionName,以与其他队列事件保持一致。

如果你的监听器引用了 $connection,请更新为 $connectionName

Queue Contract 方法新增

影响可能性:极低

Illuminate\Contracts\Queue\Queue contract 现在包含之前仅在 docblock 中声明的队列大小检查方法。

如果你维护该 contract 的自定义队列驱动实现,请为以下方法添加实现:

  • pendingSize
  • delayedSize
  • reservedSize
  • creationTimeOfOldestPendingJob

路由

域名路由注册优先级

影响可能性:低

带有显式域名的路由现在在路由匹配中优先于无域名路由。

这使得通配子域名路由即使在无域名路由注册更早的情况下也能表现一致。如果你的应用依赖于域名路由与无域名路由之间之前的注册优先级,请检查路由匹配行为。

任务调度

withScheduling 注册时机

影响可能性:极低

通过 ApplicationBuilder::withScheduling() 注册的调度任务现在推迟到 Schedule 被解析时才执行。

如果你的应用依赖于在启动过程中立即注册调度任务,可能需要调整该逻辑。

安全

请求伪造保护

影响可能性:高

Laravel 的 CSRF middleware 已从 VerifyCsrfToken 重命名为 PreventRequestForgery,现在使用 Sec-Fetch-Site 请求头进行请求来源验证。

VerifyCsrfTokenValidateCsrfToken 作为已弃用的别名保留,但直接引用应更新为 PreventRequestForgery,尤其是在测试或路由定义中排除 middleware 时:

php
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;

// Laravel <= 12.x
->withoutMiddleware([VerifyCsrfToken::class]);

// Laravel >= 13.x
->withoutMiddleware([PreventRequestForgery::class]);

middleware 配置 API 现在也提供了 preventRequestForgery(...)

Support

Manager extend 回调绑定

影响可能性:低

通过 manager extend 方法注册的自定义驱动闭包现在绑定到 manager 实例。

如果你之前在这些回调内部依赖另一个绑定对象(如 service provider 实例)作为 $this,应使用 use (...) 将这些值捕获到闭包中。

Str 工厂在测试间重置

影响可能性:低

Laravel 现在在测试结束时重置自定义 Str 工厂。

如果你的测试依赖自定义 UUID / ULID / 随机字符串工厂在测试方法之间持久化,应在每个相关测试或 setup 钩子中进行设置。

Js::from 默认使用未转义 Unicode

影响可能性:极低

Illuminate\Support\Js::from 现在默认使用 JSON_UNESCAPED_UNICODE

如果你的测试或前端输出比较依赖于转义的 Unicode 序列(例如 \u00e8),请更新你的预期值。

视图

分页 Bootstrap 视图名称

影响可能性:低

Bootstrap 3 默认的内部分页视图名称现在已明确:

txt
// Laravel <= 12.x
pagination::default
pagination::simple-default

// Laravel >= 13.x
pagination::bootstrap-3
pagination::simple-bootstrap-3

如果你的应用直接引用了旧的分页视图名称,请更新这些引用。

其他变更

我们还建议你查看 laravel/laravel GitHub 仓库中的变更。虽然这些变更大多不是必须的,但你可能希望保持这些文件与你的应用同步。其中一些变更会在本升级指南中涵盖,但其他变更(如配置文件或注释的修改)则不会。你可以使用 GitHub 比较工具轻松查看变更并选择哪些更新对你重要。