> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel 12 升级到 13 指南

> Laravel 12 到 13 的升级步骤、破坏性变更、废弃功能以及新功能亮点解析。

## 前言

Laravel 13 于 2026 年 3 月发布。本指南讲解从 Laravel 12.x 升级到 13.x 的操作步骤。

<Info>
  预计升级时间**约 10 分钟**。当然,破坏性变更对应用的影响会因规模和所用功能而异。
</Info>

### 使用 AI 升级

也可以用 [Laravel Boost](https://github.com/laravel/boost) 自动化升级。Boost 是官方的 MCP 服务器,能为 AI 助手提供分步的升级提示。装到 Laravel 12 应用后,可以在 Claude Code、Cursor、OpenCode、Gemini、VS Code 中通过 `/upgrade-laravel-v13` 斜杠命令开始升级到 Laravel 13。该命令需要 `laravel/boost ^2.0`。

即便你使用的 AI 工具不支持斜杠命令,也可以直接引用提示词文件,执行相同的升级步骤。把下面的 prompt 原样贴给 AI 即可。

```text 提示词 theme={null}
请读取 Laravel Boost 提供的提示词,完成从 Laravel 12 到 13 的升级工作。
https://raw.githubusercontent.com/laravel/boost/refs/heads/main/src/Mcp/Prompts/UpgradeLaravelv13/upgrade-laravel-v13.blade.php

- 反映 `laravel/laravel` 骨架的变更。请参考 13.x 分支,而不是 master。
- `database/migrations/*_create_cache_table.php` 不要直接改,而是创建新的迁移。
- 把 `config/session.php` 的 `serialization` 设为 `php`,即 `'serialization' => 'php'`。
- Laravel 13 中最容易让应用出错的变更是缓存的行为变化,因此请在项目中搜索缓存使用位置,只要看起来安全就在 config/cache.php 的 `serializable_classes` 中放行。

'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
    Illuminate\Support\Collection::class,
    Illuminate\Database\Eloquent\Collection::class,
],
```

***

## 按影响面分级的变更

### 影响度:高

* 依赖更新
* Laravel installer 更新
* 请求伪造防御(CSRF)

### 影响度:中

* 缓存 `serializable_classes` 设置
* Session `serialization` 设置

### 影响度:低

* 缓存前缀与 session Cookie 名
* 集合模型的序列化
* `Container::call` 与 Nullable 类的默认值
* 域名路由注册的优先级
* `JobAttempted` 事件的异常载荷
* Manager `extend` 回调的绑定
* MySQL `DELETE` 查询(JOIN / ORDER BY / LIMIT)
* 分页 Bootstrap 视图名
* 多态 pivot 表名的生成
* `QueueBusy` 事件的属性名变更
* `Str` factory 在测试间的重置

***

## 升级步骤

### 更新依赖

**影响度:高**

请更新 `composer.json` 中的以下依赖。

```json theme={null}
{
  "require": {
    "laravel/framework": "^13.0",
    "laravel/tinker": "^3.0"
  },
  "require-dev": {
    "phpunit/phpunit": "^12.0",
    "pestphp/pest": "^4.0"
  }
}
```

在使用 Laravel Boost 时也一并更新。

```json theme={null}
{
  "require": {
    "laravel/boost": "^2.0"
  }
}
```

改完之后执行:

```shell theme={null}
composer update
```

***

### 更新 Laravel installer

**影响度:高**

如果你用 Laravel installer CLI 创建新项目,请把它升到兼容 Laravel 13.x 的版本。

用 `composer global require` 安装的情况:

```shell theme={null}
composer global update laravel/installer
```

在使用 [Laravel Herd](https://herd.laravel.com) 的捆绑版本时,请把 Herd 本身升到最新版。

***

## 破坏性变更(Breaking Changes)

### 安全

#### 请求伪造防御

**影响度:高**

Laravel 的 CSRF 中间件从 `VerifyCsrfToken` 重命名为 `PreventRequestForgery`。同时新增了基于 `Sec-Fetch-Site` 头的请求来源校验。

`VerifyCsrfToken` 和 `ValidateCsrfToken` 会作为废弃别名保留,但所有直接引用它们的地方都需要改成 `PreventRequestForgery`。特别是在测试或路由定义中排除该中间件时要留意。

```php theme={null}
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(...)`。

***

### 缓存

#### 缓存前缀与 session Cookie 名

**影响度:低**

Laravel 默认的缓存及 Redis 键前缀现在使用连字符风格的后缀。默认的 session Cookie 名也改为使用 `Str::snake(...)`。

由于大多数应用都会在配置里显式设定值,所以只有依赖框架回退默认值的应用会受影响。

```php theme={null}
// 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';
```

想保留原来的行为,请在 `.env` 里显式设置。

```ini theme={null}
CACHE_PREFIX=myapp_cache_
REDIS_PREFIX=myapp_database_
SESSION_COOKIE=myapp_session
```

#### 缓存 `serializable_classes` 设置

**影响度:中**

默认的 `cache` 配置新增了 `serializable_classes` 选项,默认为 `false`。这样即使 `APP_KEY` 泄露,也能防御 PHP 反序列化 gadget 链攻击。

如果你的应用确实在缓存里存 PHP 对象,需要显式把允许反序列化的类列出来。

```php theme={null}
// config/cache.php
'serializable_classes' => [
    App\Data\CachedDashboardStats::class,
    App\Support\CachedPricingSnapshot::class,
],
```

如果之前是让任意缓存对象反序列化,请改为显式许可列表,或者迁移到非对象的缓存载荷(例如数组)。

#### Session `serialization` 设置

**影响度:中**

Laravel 13 的骨架(`laravel/laravel`)在 `config/session.php` 里加入了 `'serialization' => 'json'`。但框架内部的默认值仍然是 `php`。

<Warning>
  用 AI 工具原样应用骨架变更时,`config/session.php` 里可能会写入 `'serialization' => 'json'`。这个改动会切换 session 的序列化方式,会让在 session 中存 PHP 对象的应用出错。
</Warning>

官方升级指南没有提到这个改动。这大概意味着 **不必更改**。Laravel 有时在“上一个大版本”升级到当前版本的指南中不会记录这类变化。数年后再升级时,如果没有信息会很麻烦,所以民间记录也很重要。

要保持与 Laravel 12 及以前一致的行为,请显式设置 `'serialization' => 'php'`。

```php theme={null}
// config/session.php
'serialization' => 'php',
```

如果想启用 JSON 序列化,请事先确认 session 里没有存 PHP 对象。

***

### 容器

#### `Container::call` 与 Nullable 类的默认值

**影响度:低**

`Container::call` 在没有绑定时会尊重 nullable 类参数的默认值(和 Laravel 12 中构造注入的行为一致)。

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

// Laravel <= 12.x: 返回一个 Carbon 实例
// Laravel >= 13.x: 返回 null
```

***

### 数据库

#### MySQL `DELETE` 查询

**影响度:低**

Laravel 现在会为 MySQL 语法编译完整的、带 `ORDER BY` 和 `LIMIT` 的 `DELETE ... JOIN` 查询。

以前带 JOIN 的 DELETE 里 `ORDER BY` / `LIMIT` 子句会被忽略。Laravel 13 会把这些子句写进生成的 SQL 中。这在不支持该语法的数据库引擎上可能引发 `QueryException`。

***

### Eloquent

#### 多态 pivot 表名的生成

**影响度:低**

使用自定义 pivot 模型类的多态 pivot 模型在推断表名时,Laravel 会生成复数形式。

如果依赖此前推断出的单数形式表名,请在 pivot 模型里显式定义表名。

```php theme={null}
class RoleUser extends MorphPivot
{
    protected $table = 'role_user'; // 显式指定
}
```

#### 集合模型的序列化

**影响度:低**

Eloquent 模型集合被序列化和恢复(比如推入队列的作业)时,会为模型恢复被 eager 加载的关联。

如果你有代码依赖“反序列化后关联不存在”这一点,需要修改。

***

### 队列

#### `JobAttempted` 事件的异常载荷

**影响度:低**

`Illuminate\Queue\Events\JobAttempted` 事件用 `$exception`(异常对象或 `null`)取代了原先的 boolean 属性 `$exceptionOccurred`。

```php theme={null}
// Laravel <= 12.x
if ($event->exceptionOccurred) {
    // 发生了异常
}

// Laravel >= 13.x
if ($event->exception !== null) {
    // 发生了异常
    $exception = $event->exception;
}
```

#### `QueueBusy` 事件的属性名变更

**影响度:低**

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

```php theme={null}
// Laravel <= 12.x
$event->connection;

// Laravel >= 13.x
$event->connectionName;
```

***

### 路由

#### 域名路由注册的优先级

**影响度:低**

有明确域名的路由在匹配时会优先于无域名路由。

这样即便无域名路由先注册,catchall 的子域名路由也能一致工作。

***

### 支持

#### Manager `extend` 回调的绑定

**影响度:低**

通过 Manager 的 `extend` 方法注册的自定义驱动闭包会被绑定到 manager 实例上。

如果之前这些回调里的 `$this` 引用了别的对象(例如服务提供者实例),需要用 `use (...)` 把它捕获到闭包里。

```php theme={null}
// Laravel <= 12.x
Manager::extend('custom', function ($app) {
    return $this->createCustomDriver($app); // $this 是服务提供者
});

// Laravel >= 13.x
$provider = $this;
Manager::extend('custom', function ($app) use ($provider) {
    return $provider->createCustomDriver($app);
});
```

#### `Str` factory 在测试间的重置

**影响度:低**

Laravel 现在会在测试 teardown 时重置自定义的 `Str` factory。

如果你依赖自定义 UUID / ULID / 随机字符串 factory 在多个测试之间保持,请在每个相关测试或 setup 钩子中重新配置。

***

### 视图

#### 分页 Bootstrap 视图名

**影响度:低**

Bootstrap 3 默认的内置分页视图名变得更明确。

```php theme={null}
// Laravel <= 12.x
pagination::default
pagination::simple-default

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

如果直接引用了旧的分页视图名,请更新。

***

## 已废弃的功能

| 功能                                 | 替代                           |
| ---------------------------------- | ---------------------------- |
| `VerifyCsrfToken` 中间件              | `PreventRequestForgery`      |
| `ValidateCsrfToken` 中间件            | `PreventRequestForgery`      |
| `JobAttempted::$exceptionOccurred` | `JobAttempted::$exception`   |
| `QueueBusy::$connection`           | `QueueBusy::$connectionName` |

***

## 契约新增

**影响度:非常低**

只对有自定义实现的场景有影响。

### `Dispatcher` 契约

`Illuminate\Contracts\Bus\Dispatcher` 契约新增了 `dispatchAfterResponse($command, $handler = null)` 方法。

### `ResponseFactory` 契约

`Illuminate\Contracts\Routing\ResponseFactory` 契约新增了 `eventStream` 签名。

### `MustVerifyEmail` 契约

`Illuminate\Contracts\Auth\MustVerifyEmail` 契约新增了 `markEmailAsUnverified()`。

### `Queue` 契约

`Illuminate\Contracts\Queue\Queue` 契约新增了以下队列体积检查方法(以前只在 docblock 中声明):

* `pendingSize`
* `delayedSize`
* `reservedSize`
* `creationTimeOfOldestPendingJob`

### `Store` / `Repository` 契约

缓存契约新增了用于延长 TTL 的 `touch` 方法。

```php theme={null}
// Illuminate\Contracts\Cache\Store
public function touch($key, $seconds);
```

***

## 新功能亮点

### AI 辅助升级(Laravel Boost)

Laravel Boost 是官方 MCP 服务器。它与 AI 编辑器联动,通过 `/upgrade-laravel-v13` 命令半自动完成升级。

### 通过 `Sec-Fetch-Site` 头做来源校验

`PreventRequestForgery` 中间件增加了基于 `Sec-Fetch-Site` 头的来源校验,加固了 CSRF 保护。

### 安全的缓存反序列化

通过 `serializable_classes` 设置,只有列入许可的类才会被反序列化。对 PHP 反序列化攻击的安全性得到提升。

### SSE(Server-Sent Events)的 `eventStream`

`ResponseFactory` 契约新增了 `eventStream`,改进了 Server-Sent Events 支持。

### 队列可观测性提升

`Queue` 契约的 `pendingSize`、`delayedSize`、`reservedSize` 等方法让你可以更细粒度地监控队列状态。

***

## 常见迁移问题与解决方案

### 问题:CSRF 相关测试失败

\*\*症状:\*\*引用 `VerifyCsrfToken` 的测试因“找不到类”而失败。

\*\*解决:\*\*把所有引用都改为 `PreventRequestForgery`。

```php theme={null}
// Before
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
->withoutMiddleware([VerifyCsrfToken::class]);

// After
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
->withoutMiddleware([PreventRequestForgery::class]);
```

### 问题:缓存中的对象无法恢复

\*\*症状:\*\*从缓存取到的数据变成 `null`,或抛 `UnserializationFailedException`。

\*\*解决:\*\*在 `config/cache.php` 的 `serializable_classes` 中加入要使用的类,或把缓存的值转成数组。

```php theme={null}
'serializable_classes' => [
    App\Models\User::class,
    App\Data\SomeData::class,
],
```

### 问题:`JobAttempted` 监听器不工作

**症状:**`$event->exceptionOccurred` 变成 `null` 或报未定义错误。

\*\*解决:\*\*改成 `$event->exception !== null`。

```php theme={null}
// Before
if ($event->exceptionOccurred) { ... }

// After
if ($event->exception !== null) { ... }
```

### 问题:session 失效

\*\*症状:\*\*升级后用户被强制登出。

\*\*解决:\*\*默认的 session Cookie 名变了。在 `.env` 里显式设置 `SESSION_COOKIE` 以保留原值。

```ini theme={null}
SESSION_COOKIE=laravel_session
```

### 问题:找不到缓存键

\*\*症状:\*\*升级后缓存 miss 增多。

\*\*解决:\*\*缓存前缀变了。在 `.env` 里设置 `CACHE_PREFIX`,或清理缓存。

```shell theme={null}
php artisan cache:clear
```

***

## 参考资料

* [官方升级指南(英文)](https://laravel.com/docs/13.x/upgrade)
* [laravel/laravel 仓库差异(12.x → 13.x)](https://github.com/laravel/laravel/compare/12.x...13.x)
* [Laravel Shift](https://laravelshift.com) —— 自动化升级的社区服务
* [Laravel Boost](https://github.com/laravel/boost) —— AI 辅助升级的 MCP 服务器


## Related topics

- [Laravel 11 升级到 12 指南](/zh/blog/upgrade-11-to-12.md)
- [Laravel 8 升级到 9](/zh/blog/upgrade-8-to-9.md)
- [Laravel 13 新功能汇总](/zh/blog/laravel-13-new-features.md)
- [Laravel 9 升级到 10](/zh/blog/upgrade-9-to-10.md)
- [Laravel 10 升级到 11](/zh/blog/upgrade-10-to-11.md)
