Skip to content
全部文档

升级指南

高影响变更

中等影响变更

低影响变更

从 12.x 升级到 13.0

预计升级时间:10 分钟

INFO

我们尽量记录每一处可能的破坏性变更。由于部分变更位于框架较冷门的区域,其中只有一部分可能真正影响你的应用。为节省时间,可使用 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 to ^13.0
  • laravel/boost to ^2.0
  • laravel/tinker to ^3.0
  • phpunit/phpunit to ^12.0
  • pestphp/pest to ^4.0

更新 Laravel 安装器

若使用 Laravel 安装器 CLI 创建新应用,应更新安装器以兼容 Laravel 13.x。

若通过 composer global require 安装了 Laravel 安装器,可用 composer global update 更新:

shell
composer global update laravel/installer

或者,若使用的是 Laravel Herd 捆绑的 Laravel 安装器,应将 Herd 更新到最新版本。

缓存

影响可能性:低

Laravel 默认的缓存与 Redis 键前缀现在使用连字符后缀。

对大多数应用而言该变更不适用,因为应用级配置文件通常已定义这些值。它主要影响在缺少对应应用配置时依赖框架级回退配置的应用。

若应用依赖这些生成的默认值,升级后缓存键与会话 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::slug((string) env('APP_NAME', 'laravel')).'-session';

若要保留先前行为,请在环境中显式配置 CACHE_PREFIXREDIS_PREFIXSESSION_COOKIE

StoreRepository 契约:touch

影响可能性:极低

缓存契约现在包含用于延长缓存项 TTL 的 touch 方法。若维护自定义缓存存储实现,应添加该方法:

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

缓存 serializable_classes 配置

影响可能性:中等

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

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

若应用此前依赖反序列化任意缓存对象,需迁移为显式类白名单,或改用非对象缓存载荷(例如数组)。

容器

Container::call 与可空类默认值

影响可能性:低

当不存在绑定时,Container::call 现在会尊重可空类参数的默认值,与 Laravel 12 引入的构造函数注入行为一致:

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

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

若你的方法调用注入逻辑依赖先前行为,可能需要更新。

契约

Dispatcher 契约:dispatchAfterResponse

影响可能性:极低

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

若维护自定义 dispatcher 实现,请在类中添加该方法。

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

JOINORDER BYLIMIT 的 MySQL DELETE 查询

影响可能性:低

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

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

Eloquent

模型启动与嵌套实例化

影响可能性:极低

在模型仍在启动时创建新模型实例现已禁止,并会抛出 LogicException

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

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

    // No longer allowed during booting...
    (new static())->getTable();
}

请将此类逻辑移出启动周期,以避免嵌套启动。

多态中间表名称生成

影响可能性:低

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

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

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

影响可能性:低

当 Eloquent 模型集合被序列化并恢复时(例如在队列任务中),现在会为集合中的模型恢复预加载关联。

若代码依赖反序列化后关联不存在,可能需要调整该逻辑。

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 属性。

在先前版本中,缺失模型仍可能导致你期望被删除的队列通知任务失败。

队列

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 契约新增方法

影响可能性:极低

Illuminate\Contracts\Queue\Queue 契约现在包含先前仅在文档块中声明的队列大小检查方法。

若维护该契约的自定义队列驱动实现,请实现下列方法:

  • pendingSize
  • delayedSize
  • reservedSize
  • creationTimeOfOldestPendingJob

路由

域名路由注册优先级

影响可能性:低

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

这使得即便无域名路由更早注册,通配子域名路由也能行为一致。若应用依赖域名与无域名路由之间先前的注册优先级,请复查路由匹配行为。

会话

会话 serialization 配置

影响可能性:低

为帮助防止 PHP 反序列化 gadget 链攻击,默认应用骨架现在在 config/session.php 中将会话 serialization 选项设为 json

若升级现有应用并与 Laravel 13 骨架同步配置文件,将该值从 php 更新为 json 会使所有活动用户会话失效。

若希望在升级期间无缝保留活动会话,应确保该值仍为 php。不过,若应用不在会话中存储 PHP 对象,且可以接受用户重新认证,建议将该值更新为 json 以提高安全性。

任务调度

withScheduling 注册时机

影响可能性:极低

通过 ApplicationBuilder::withScheduling() 注册的调度现在会延迟到解析 Schedule 时执行。

若应用依赖引导期间立即注册调度的时机,可能需要调整该逻辑。

安全

请求伪造防护

影响可能性:高

Laravel 的 CSRF 中间件已从 VerifyCsrfToken 重命名为 PreventRequestForgery,并增加了使用 Sec-Fetch-Site 头的请求来源校验。

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

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]);

中间件配置 API 现在也提供 preventRequestForgery(...)

支持类

Manager extend 回调绑定

影响可能性:低

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

若此前依赖其他绑定对象(例如服务提供者实例)作为这些回调中的 $this,应使用 use (...) 将这些值捕获进闭包。

Str 工厂在测试间重置

影响可能性:低

Laravel 现在会在测试拆除阶段重置自定义 Str 工厂。

若测试依赖自定义 UUID / ULID / 随机字符串工厂在测试方法之间保持,应在每个相关测试或 setup 钩子中重新设置。

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

影响可能性:极低

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

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

工具

Symfony PHP 8.5 Polyfill 与全局函数冲突

影响可能性:低

Laravel 13 引入了对 symfony/polyfill-php85 的依赖。在低于 8.5 的 PHP 版本上,该 polyfill 会定义 array_first()array_last() 等全局函数(除非它们已在引导早期被定义)。

这些函数可能与 laravel/helpers 等遗留辅助包,或使用同名的自定义全局辅助函数冲突。例如,历史上的 array_first() 辅助函数接受回调以返回第一个匹配元素,而 polyfill 版本仅返回数组的第一个元素。

为避免冲突并确保跨 PHP 版本行为一致,应优先使用 Illuminate\Support\Arr 方法:

php
use Illuminate\Support\Arr;

Arr::first($array, function ($value) {
  return /* condition */;
});

视图

分页 Bootstrap 视图名称

影响可能性:低

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

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

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

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

其他

我们也鼓励你查看 laravel/laravel GitHub 仓库 中的变更。其中许多变更并非必需,但你可能希望让这些文件与应用保持同步。本升级指南会涵盖部分变更,但配置文件或注释等其他变更不会。你可使用 GitHub 比较工具 轻松查看变更,并选择对你重要的更新。