Skip to content
全部文档

升级指南

高影响变更

中等影响变更

低影响变更

从 11.x 升级到 12.0

预计升级时间:5 分钟

INFO

我们尽量记录每一处可能的破坏性变更。由于部分变更位于框架较冷门的区域,其中只有一部分可能真正影响你的应用。想节省时间?可使用 Laravel Shift 协助自动化升级。

更新依赖

影响可能性:高

需要 PHP 8.2.0

Laravel 现在要求 PHP 8.2.0 或更高版本。

需要 curl 7.34.0

Laravel 的 HTTP 客户端现在要求 curl 7.34.0 或更高版本。

Composer 依赖

应在应用的 composer.json 中更新下列依赖:

  • `laravel/framework` 升级到 `^11.0`
  • `nunomaduro/collision` 升级到 `^8.1`
  • `laravel/breeze` 升级到 `^2.0`(若已安装)
  • `laravel/cashier` 升级到 `^15.0`(若已安装)
  • `laravel/dusk` 升级到 `^8.0`(若已安装)
  • `laravel/jetstream` 升级到 `^5.0`(若已安装)
  • `laravel/octane` 升级到 `^2.3`(若已安装)
  • `laravel/passport` 升级到 `^12.0`(若已安装)
  • `laravel/sanctum` 升级到 `^4.0`(若已安装)
  • `laravel/scout` 升级到 `^10.0`(若已安装)
  • `laravel/spark-stripe` 升级到 `^5.0`(若已安装)
  • `laravel/telescope` 升级到 `^5.0`(若已安装)
  • `livewire/livewire` 升级到 `^3.4`(若已安装)
  • `inertiajs/inertia-laravel` 升级到 `^1.0`(若已安装)

若应用使用了 Laravel Cashier Stripe、Passport、Sanctum、Spark Stripe 或 Telescope,需要将它们的迁移发布到你的应用中。Cashier Stripe、Passport、Sanctum、Spark Stripe 和 Telescope 不再自动从其自身的 migrations 目录加载迁移。因此,应运行以下命令将这些包的迁移发布到应用中:

bash
php artisan vendor:publish --tag=cashier-migrations
php artisan vendor:publish --tag=passport-migrations
php artisan vendor:publish --tag=sanctum-migrations
php artisan vendor:publish --tag=spark-migrations
php artisan vendor:publish --tag=telescope-migrations

此外,还应查阅这些包各自的升级指南,以确保了解其他破坏性变更:

若你已手动安装 Laravel 安装器,应通过 Composer 更新该安装器:

bash
composer global require laravel/installer:^5.6

最后,若你之前曾将 doctrine/dbal 加入应用,现在可以移除该 Composer 依赖,因为 Laravel 已不再依赖此包。

应用结构

Laravel 11 引入了默认文件更少的新默认应用结构。也就是说,新建的 Laravel 应用包含更少的服务提供者、中间件与配置文件。

不过,我们不建议从 Laravel 10 升级到 Laravel 11 的应用去迁移应用结构,因为 Laravel 11 也经过仔细调优以继续支持 Laravel 10 的应用结构。

认证

密码重新哈希

影响可能性:低

若自密码上次哈希以来,哈希算法的「工作因子」已更新,Laravel 11 会在认证过程中自动重新哈希用户密码。

通常这不会影响你的应用;不过,若 User 模型的「密码」字段名不是 password,应通过模型的 authPasswordName 属性指定该字段名:

php
protected $authPasswordName = 'custom_password_field';

或者,可在应用的 config/hashing.php 配置文件中加入 rehash_on_login 选项以禁用密码重新哈希:

'rehash_on_login' => false,

UserProvider 契约

影响可能性:低

Illuminate\Contracts\Auth\UserProvider 契约新增了 rehashPasswordIfRequired 方法。当应用的哈希算法工作因子发生变化时,该方法负责重新哈希并将用户密码存回存储。

若你的应用或包定义了实现该接口的类,应在实现中加入新的 rehashPasswordIfRequired 方法。可参考 Illuminate\Auth\EloquentUserProvider 类中的实现:

php
public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false);

Authenticatable 契约

影响可能性:低

Illuminate\Contracts\Auth\Authenticatable 契约新增了 getAuthPasswordName 方法。该方法负责返回可认证实体的密码列名。

若你的应用或包定义了实现该接口的类,应在实现中加入新的 getAuthPasswordName 方法:

php
public function getAuthPasswordName()
{
    return 'password';
}

Laravel 自带的默认 User 模型会自动获得该方法,因为该方法已包含在 Illuminate\Auth\Authenticatable trait 中。

AuthenticationException

影响可能性:极低

Illuminate\Auth\AuthenticationException 类的 redirectTo 方法现在要求第一个参数为 Illuminate\Http\Request 实例。若你在手动捕获该异常并调用 redirectTo,应相应更新代码:

php
if ($e instanceof AuthenticationException) {
    $path = $e->redirectTo($request);
}

注册时的邮箱验证通知

影响可能性:极低

若应用的 EventServiceProvider 尚未注册,SendEmailVerificationNotification 监听器现在会自动注册到 Registered 事件。若你的 EventServiceProvider 未注册该监听器,且你不希望 Laravel 自动注册,应在应用的 EventServiceProvider 中定义一个空的 configureEmailVerification 方法:

php
protected function configureEmailVerification()
{
    // ...
}

缓存

缓存键前缀

影响可能性:极低

此前,若为 DynamoDB、Memcached 或 Redis 缓存存储定义了缓存键前缀,Laravel 会在前缀后追加 :。在 Laravel 11 中,缓存键前缀不再自动加上 : 后缀。若希望保持先前的前缀行为,可手动在缓存键前缀后加上 :

集合

Enumerable 契约

影响可能性:低

Illuminate\Support\Enumerable 契约的 dump 方法已更新为接受可变参数 ...$args。若你实现了该接口,应相应更新实现:

php
public function dump(...$args);

数据库

SQLite 3.26.0 及以上

影响可能性:高

若应用使用 SQLite 数据库,则需要 SQLite 3.26.0 或更高版本。

Eloquent 模型的 casts 方法

影响可能性:低

基础 Eloquent 模型类现在定义了 casts 方法以支持属性转换的声明。若应用中某个模型定义了名为 casts 的关联,可能会与基础 Eloquent 模型类上现有的 casts 方法冲突。

修改列

影响可能性:高

修改列时,现在必须显式包含希望在变更后仍保留在列定义上的所有修饰符。任何缺失的属性都会被丢弃。例如,要保留 unsigneddefaultcomment 属性,即使先前迁移已为该列设置过这些属性,修改列时也必须显式调用每个修饰符。

例如,假设你有一个迁移,创建了带有 unsigneddefaultcomment 属性的 votes 列:

php
Schema::create('users', function (Blueprint $table) {
    $table->integer('votes')->unsigned()->default(1)->comment('The vote count');
});

随后,你又编写一个迁移,将该列改为也可为 nullable

php
Schema::table('users', function (Blueprint $table) {
    $table->integer('votes')->nullable()->change();
});

在 Laravel 10 中,该迁移会保留列上的 unsigneddefaultcomment 属性。但在 Laravel 11 中,迁移现在还必须包含先前在该列上定义的所有属性,否则这些属性会被丢弃:

php
Schema::table('users', function (Blueprint $table) {
    $table->integer('votes')
        ->unsigned()
        ->default(1)
        ->comment('The vote count')
        ->nullable()
        ->change();
});

change 方法不会更改列上的索引。因此,修改列时可用索引修饰符显式添加或删除索引:

php
// Add an index...
$table->bigIncrements('id')->primary()->change();

// Drop an index...
$table->char('postal_code', 10)->unique(false)->change();

若不想更新应用中所有现有的「change」迁移以保留列的既有属性,可以简单地压缩迁移

bash
php artisan schema:dump

压缩迁移后,Laravel 会先使用应用的 schema 文件「迁移」数据库,然后再运行任何待执行的迁移。

浮点类型

影响可能性:高

doublefloat 迁移列类型已重写,以在所有数据库上保持一致。

double 列类型现在会创建不含总位数与小数位数(小数点后位数)的、与 DOUBLE 等价的列,这是标准 SQL 语法。因此,可移除 $total$places 参数:

php
$table->double('amount');

float 列类型现在会创建不含总位数与小数位数(小数点后位数)的、与 FLOAT 等价的列,但可选用可选的 $precision 来指定存储大小为 4 字节单精度列或 8 字节双精度列。因此,可移除 $total$places 参数,并按需以及根据数据库文档指定可选的 $precision

php
$table->float('amount', precision: 53);

unsignedDecimalunsignedDoubleunsignedFloat 方法已被移除,因为这些列类型的 unsigned 修饰符已被 MySQL 弃用,且从未在其他数据库系统上标准化。不过,若仍希望对这些列类型使用已弃用的 unsigned 属性,可在列定义上链式调用 unsigned 方法:

php
$table->decimal('amount', total: 8, places: 2)->unsigned();
$table->double('amount')->unsigned();
$table->float('amount', precision: 53)->unsigned();

专用 MariaDB 驱动

影响可能性:极低

连接 MariaDB 数据库时不再始终使用 MySQL 驱动,Laravel 11 新增了专用的 MariaDB 数据库驱动。

若应用连接 MariaDB 数据库,可将连接配置更新为新的 mariadb 驱动,以便日后受益于 MariaDB 特有功能:

'driver' => 'mariadb',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
// ...

目前,新的 MariaDB 驱动行为与现有 MySQL 驱动基本一致,唯一例外是:uuid schema 构建器方法会创建原生 UUID 列,而不是 char(36) 列。

若现有迁移使用了 uuid schema 构建器方法,且你选择使用新的 mariadb 数据库驱动,应将迁移中对 uuid 方法的调用更新为 char,以避免破坏性变更或意外行为:

php
Schema::table('users', function (Blueprint $table) {
    $table->char('uuid', 36);

    // ...
});

空间类型

影响可能性:低

数据库迁移中的空间列类型已重写,以在所有数据库上保持一致。因此,可从迁移中移除 pointlineStringpolygongeometryCollectionmultiPointmultiLineStringmultiPolygonmultiPolygonZ 方法,改用 geometrygeography 方法:

php
$table->geometry('shapes');
$table->geography('coordinates');

若要在 MySQL、MariaDB 与 PostgreSQL 上显式限制列中所存值的类型或空间参考系统标识符,可将 subtypesrid 传给该方法:

php
$table->geometry('dimension', subtype: 'polygon', srid: 0);
$table->geography('latitude', subtype: 'point', srid: 4326);

相应地,PostgreSQL 语法中的 isGeometryprojection 列修饰符也已移除。

移除 Doctrine DBAL

影响可能性:低

下列与 Doctrine DBAL 相关的类与方法已被移除。Laravel 已不再依赖该包;对于先前需要自定义类型才能正确创建与修改的各类列类型,现在也不再需要注册自定义 Doctrine 类型:

  • `Illuminate\Database\Schema\Builder::$alwaysUsesNativeSchemaOperationsIfPossible` 类属性
  • `Illuminate\Database\Schema\Builder::useNativeSchemaOperationsIfPossible()` 方法
  • `Illuminate\Database\Connection::usingNativeSchemaOperations()` 方法
  • `Illuminate\Database\Connection::isDoctrineAvailable()` 方法
  • `Illuminate\Database\Connection::getDoctrineConnection()` 方法
  • `Illuminate\Database\Connection::getDoctrineSchemaManager()` 方法
  • `Illuminate\Database\Connection::getDoctrineColumn()` 方法
  • `Illuminate\Database\Connection::registerDoctrineType()` 方法
  • `Illuminate\Database\DatabaseManager::registerDoctrineType()` 方法
  • `Illuminate\Database\PDO` 目录
  • `Illuminate\Database\DBAL\TimestampType` 类
  • `Illuminate\Database\Schema\Grammars\ChangeColumn` 类
  • `Illuminate\Database\Schema\Grammars\RenameColumn` 类
  • `Illuminate\Database\Schema\Grammars\Grammar::getDoctrineTableDiff()` 方法

此外,也不再需要通过应用 database 配置文件中的 dbal.types 注册自定义 Doctrine 类型。

若你此前使用 Doctrine DBAL 检查数据库及其相关表,可改用 Laravel 新的原生 schema 方法(如 Schema::getTables()Schema::getColumns()Schema::getIndexes()Schema::getForeignKeys() 等)。

已弃用的 Schema 方法

影响可能性:极低

基于 Doctrine 的已弃用方法 Schema::getAllTables()Schema::getAllViews()Schema::getAllTypes() 已移除,改为使用 Laravel 原生的 Schema::getTables()Schema::getViews()Schema::getTypes() 方法。

在使用 PostgreSQL 与 SQL Server 时,新的 schema 方法均不接受三段式引用(例如 database.schema.table)。因此,应改用 connection() 声明数据库:

php
Schema::connection('database')->hasTable('schema.table');

Schema 构建器的 getColumnType() 方法

影响可能性:极低

Schema::getColumnType() 方法现在始终返回给定列的实际类型,而不再是 Doctrine DBAL 的等价类型。

数据库连接接口

影响可能性:极低

Illuminate\Database\ConnectionInterface 接口新增了 scalar 方法。若你自行实现该接口,应在实现中加入 scalar 方法:

php
public function scalar($query, $bindings = [], $useReadPdo = true);

日期

Carbon 3

影响可能性:中等

Laravel 11 同时支持 Carbon 2 与 Carbon 3。Carbon 是 Laravel 及生态中各包广泛使用的日期处理库。若升级到 Carbon 3,请注意 diffIn* 方法现在会返回浮点数,并可能返回负值以表示时间方向,这与 Carbon 2 有显著不同。请查阅 Carbon 的变更日志文档,了解如何处理这些及其他变更的详细说明。

邮件

Mailer 契约

影响可能性:极低

Illuminate\Contracts\Mail\Mailer 契约新增了 sendNow 方法。若你的应用或包手动实现了该契约,应在实现中加入新的 sendNow 方法:

php
public function sendNow($mailable, array $data = [], $callback = null);

将服务提供者发布到应用

影响可能性:极低

若你编写的 Laravel 包会手动将服务提供者发布到应用的 app/Providers 目录,并手动修改应用的 config/app.php 配置文件以注册该服务提供者,应更新包以使用新的 ServiceProvider::addProviderToBootstrapFile 方法。

addProviderToBootstrapFile 方法会自动将你发布的服务提供者加入应用的 bootstrap/providers.php 文件,因为在新建的 Laravel 11 应用中,config/app.php 配置文件里已不存在 providers 数组。

php
use Illuminate\Support\ServiceProvider;

ServiceProvider::addProviderToBootstrapFile(Provider::class);

队列

BatchRepository 接口

影响可能性:极低

Illuminate\Bus\BatchRepository 接口新增了 rollBack 方法。若你在自己的包或应用中实现了该接口,应在实现中加入该方法:

php
public function rollBack();

数据库事务中的同步任务

影响可能性:极低

此前,同步任务(使用 sync 队列驱动的任务)会立即执行,无论队列连接的 after_commit 配置选项是否为 true,也不论是否在任务上调用了 afterCommit 方法。

在 Laravel 11 中,同步队列任务现在会遵守队列连接或任务的「after commit」配置。

速率限制

按秒速率限制

影响可能性:中等

Laravel 11 支持按秒进行速率限制,而不再仅限于按分钟粒度。与此变更相关,有若干潜在破坏性变更需要注意。

GlobalLimit 类的构造函数现在接受秒而不是分钟。该类未写入文档,通常也不会被应用直接使用:

php
new GlobalLimit($attempts, 2 * 60);

Limit 类的构造函数现在接受秒而不是分钟。文档中对该类的用法均限于静态构造方法,例如 Limit::perMinuteLimit::perSecond。不过,若你手动实例化该类,应更新应用,向构造函数传入秒数:

php
new Limit($key, $attempts, 2 * 60);

Limit 类的 decayMinutes 属性已重命名为 decaySeconds,现在存放的是秒而不是分钟。

Illuminate\Queue\Middleware\ThrottlesExceptionsIlluminate\Queue\Middleware\ThrottlesExceptionsWithRedis 类的构造函数现在接受秒而不是分钟:

php
new ThrottlesExceptions($attempts, 2 * 60);
new ThrottlesExceptionsWithRedis($attempts, 2 * 60);

Cashier Stripe

更新 Cashier Stripe

影响可能性:高

Laravel 11 不再支持 Cashier Stripe 14.x。因此,应在应用的 composer.json 文件中将 Laravel Cashier Stripe 依赖更新为 ^15.0

Cashier Stripe 15.0 不再自动从其自身的 migrations 目录加载迁移。你应改为运行以下命令,将 Cashier Stripe 的迁移发布到应用中:

shell
php artisan vendor:publish --tag=cashier-migrations

请查阅完整的 Cashier Stripe 升级指南 以了解其他破坏性变更。

Spark(Stripe)

更新 Spark Stripe

影响可能性:高

Laravel 11 不再支持 Laravel Spark Stripe 4.x。因此,应在应用的 composer.json 文件中将 Laravel Spark Stripe 依赖更新为 ^5.0

Spark Stripe 5.0 不再自动从其自身的 migrations 目录加载迁移。你应改为运行以下命令,将 Spark Stripe 的迁移发布到应用中:

shell
php artisan vendor:publish --tag=spark-migrations

请查阅完整的 Spark Stripe 升级指南 以了解其他破坏性变更。

Passport

更新 Passport

影响可能性:高

Laravel 11 不再支持 Laravel Passport 11.x。因此,应在应用的 composer.json 文件中将 Laravel Passport 依赖更新为 ^12.0

Passport 12.0 不再自动从其自身的 migrations 目录加载迁移。你应改为运行以下命令,将 Passport 的迁移发布到应用中:

shell
php artisan vendor:publish --tag=passport-migrations

此外,password grant 类型默认已禁用。可在应用 AppServiceProviderboot 方法中调用 enablePasswordGrant 方法以启用:

php
public function boot(): void
{
    Passport::enablePasswordGrant();
}

Sanctum

更新 Sanctum

影响可能性:高

Laravel 11 不再支持 Laravel Sanctum 3.x。因此,应在应用的 composer.json 文件中将 Laravel Sanctum 依赖更新为 ^4.0

Sanctum 4.0 不再自动从其自身的 migrations 目录加载迁移。你应改为运行以下命令,将 Sanctum 的迁移发布到应用中:

shell
php artisan vendor:publish --tag=sanctum-migrations

然后,在应用的 config/sanctum.php 配置文件中,应将 authenticate_sessionencrypt_cookiesvalidate_csrf_token 中间件的引用更新为如下内容:

'middleware' => [
    'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
    'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
    'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
],

Telescope

更新 Telescope

影响可能性:高

Laravel 11 不再支持 Laravel Telescope 4.x。因此,应在应用的 composer.json 文件中将 Laravel Telescope 依赖更新为 ^5.0

Telescope 5.0 不再自动从其自身的 migrations 目录加载迁移。你应改为运行以下命令,将 Telescope 的迁移发布到应用中:

shell
php artisan vendor:publish --tag=telescope-migrations

Spatie Once 包

影响可能性:中等

Laravel 11 现在自带 once 函数,用于确保给定闭包只执行一次。因此,若应用依赖 spatie/once 包,应从应用的 composer.json 中移除该包,以避免冲突。

其他

我们也建议查看 laravel/laravel GitHub 仓库中的变更。其中许多并非必须,但你可能希望与应用保持同步。本升级指南会涵盖部分变更,另一些(例如配置文件或注释的改动)则不会。你可用 GitHub 对比工具轻松查看差异,并选择对你重要的更新。