升级指南

从 10.x 升级到 11.0

高影响变化

  • 更新依赖项

  • 应用结构

  • 浮动点类型

  • 修改列

  • SQLite 最低版本要求

  • 更新 Sanctum

中等影响变化

  • Carbon 3

  • 密码重新哈希

  • 每秒限流

  • Spatie Once 包

低影响变化

  • Doctrine DBAL 移除

  • Eloquent 模型的 casts 方法

  • 空间(Spatial)类型

  • Enumerable 接口

  • UserProvider 接口

  • Authenticatable 接口

从 10.x 升级到 11.0

预计升级时间:15 分钟

我们尽力记录每一个可能的破坏性改变。由于有些破坏性改变出现在框架的较为隐蔽部分,因此只有部分变化可能会影响到你的应用。如果想节省时间,可以使用 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 StripeTelescope,你需要发布它们的迁移文件到应用中。因为从 Laravel 11 起,这些包不再自动加载它们自己的迁移文件。你需要运行以下命令来发布这些迁移:

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 更新安装器:

composer global require laravel/installer:^5.6

最后,如果你之前手动添加了 doctrine/dbal 依赖项,可以将其从 composer.json 中移除,因为 Laravel 现在不再依赖此包。

应用结构

Laravel 11 引入了新的默认应用结构,减少了默认文件的数量,特别是服务提供者、中间件和配置文件等。

然而,我们不推荐 Laravel 10 应用在升级到 Laravel 11 后尝试迁移其应用结构,因为 Laravel 11 已经经过调优,可以支持 Laravel 10 的应用结构。

身份验证

密码重新哈希

影响的可能性:低

Laravel 11 将会在身份验证过程中自动重新哈希用户的密码,如果密码的哈希算法的“工作因子”(work factor)自上次哈希以来有所更新。

通常,这不会干扰您的应用程序;但是,如果您的 User 模型的 password 字段名称不同于默认的 password,您应该通过模型的 authPasswordName 属性指定该字段的名称:

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 类中找到参考实现。

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

Authenticatable 接口

影响的可能性:低

Illuminate\Contracts\Auth\Authenticatable 接口新增了一个 getAuthPasswordName 方法。此方法用于返回你的认证实体的密码字段名称。

如果您的应用程序或包定义了一个实现此接口的类,您应该在您的实现中添加新的 getAuthPasswordName 方法。

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

Laravel 默认的 User 模型会自动接收到这个方法,因为该方法包含在 Illuminate\Auth\Authenticatable trait 中。

认证异常类(AuthenticationException Class)

影响可能性:非常低

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

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

注册时的电子邮件验证通知(Email Verification Notification on Registration)

影响可能性:非常低

如果您的应用程序的 EventServiceProvider 尚未注册 SendEmailVerificationNotification 监听器,则此监听器现在会在 Registered 事件上自动注册。如果您的应用程序的 EventServiceProvider 没有注册该监听器,并且您不希望 Laravel 自动为您注册它,您应该在应用程序的 EventServiceProvider 中定义一个空的 configureEmailVerification 方法:

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

缓存

缓存键前缀

影响的可能性:非常低

以前,如果为 DynamoDB、Memcached 或 Redis 缓存存储定义了缓存键前缀,Laravel 会在前缀后添加一个冒号(:)。在 Laravel 11 中,缓存键前缀不再自动添加冒号(:)。如果您希望保持之前的前缀行为,可以手动在缓存键前缀中添加冒号(:)后缀。

集合(Collections)

Enumerable 接口

影响可能性:低

Illuminate\Support\Enumerable 合同的 dump 方法已更新,接受一个变长参数 …​$args。如果您正在实现此接口,请相应地更新您的实现:

public function dump(...$args);

数据库

SQLite 3.26.0+

影响的可能性:高

如果你的应用使用 SQLite 数据库,则必须升级到 SQLite 3.26.0 或更高版本。

Eloquent 模型的 casts 方法

影响可能性:低

基础的 Eloquent 模型类现在定义了一个 casts 方法,以支持属性类型的转换。如果您的应用中的某个模型定义了一个 casts 关系,它可能与现在在基础 Eloquent 模型类中存在的 casts 方法发生冲突。

修改列

影响可能性:高

在修改列时,您现在必须显式包含所有您希望在列定义更改后保留的修改器。任何缺失的属性将会被丢弃。例如,为了保留 unsigneddefaultcomment 属性,您必须在更改列时显式调用每个修改器,即使这些属性已经由之前的迁移分配给该列。

例如,假设您有一个迁移,创建了一个 votes 列,具有 unsigneddefaultcomment 属性:

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

后来,您编写了一个迁移,将该列更改为可以为 nullable

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

在 Laravel 10 中,这个迁移将会保留 unsigneddefaultcomment 属性。然而,在 Laravel 11 中,迁移现在必须显式包括所有先前定义的属性,否则它们将被丢弃:

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

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

// 添加索引...
$table->bigIncrements('id')->primary()->change();

// 删除索引...
$table->char('postal_code', 10)->unique(false)->change();

如果您不想更新应用中所有现有的 "change" 迁移来保留列的现有属性,您可以简单地 压缩您的迁移

php artisan schema:dump

一旦迁移被压缩,Laravel 会在运行任何待处理迁移之前,使用应用程序的架构文件来 “迁移” 数据库。

浮动点类型

影响的可能性:高

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

double 类型现在创建没有总数字和小数位的标准 SQL DOUBLE 列,因此你可以去除 $total$places 参数:

$table->double('amount');

float 列类型现在会创建一个等效的 FLOAT 列,没有总位数和小数位数的限制,但可以通过可选的 $precision 参数来确定存储大小为 4 字节单精度列或 8 字节双精度列。因此,您可以移除 $total$places 的参数,并根据您的数据库文档,指定可选的 $precision 为所需的值。

// 对于 float('amount', precision: 53),precision: 53 指的是总共可以存储 53 位数字,包括小数点前后的所有位数。
// 换句话说,浮点数的总精度为 53 位数字。
$table->float('amount', precision: 53);

unsignedDecimalunsignedDoubleunsignedFloat 方法已被移除,因为 MySQL 已弃用这些列类型的 unsigned 修饰符,而且其它数据库系统从未对此进行标准化。然而,如果您希望继续使用这些列类型的弃用 unsigned 属性,可以将 unsigned 方法链式调用到列定义中:

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

专用 MariaDB 驱动

影响可能性:非常低

Laravel 11 为 MariaDB 数据库提供了一个专用的数据库驱动,而不再总是使用 MySQL 驱动。

如果您的应用程序连接到 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 类型,以避免破坏性更改或意外行为:

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

    // ...
});

空间类型

影响可能性:低

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

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

如果您希望在 MySQL、MariaDB 和 PostgreSQL 中显式限制列存储的值类型或空间参考系统标识符(SRID),可以将 subtypesrid 参数传递给方法:

$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() 方法

此外,通过在应用程序的数据库配置文件中使用 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 时,新的模式方法不再接受三部分引用(例如 database.schema.table)。因此,您应该使用 connection() 来声明数据库,如下所示:

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

Schema Builder getColumnType() 方法

影响可能性:非常低

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

数据库连接接口

影响可能性:非常低

Illuminate\Database\ConnectionInterface 接口新增了一个 scalar 方法。如果您正在定义自己对该接口的实现,应该在实现中添加 scalar 方法:

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

Dates

Carbon 3

影响的可能性:中

Laravel 11 支持 Carbon 2 和 Carbon 3。Carbon 是一个在 Laravel 和整个生态系统中广泛使用的日期处理库。如果你升级到 Carbon 3,请注意 diffIn* 方法现在返回浮动点数字,并且可能返回负值,表示时间的方向。这与 Carbon 2 的行为有很大不同。请查看 Carbon 的 变更 日志和 文档,以获取有关如何处理这些及其它更改的详细信息。

Mail

Mailer 接口

影响可能性:非常低

Illuminate\Contracts\Mail\Mailer 接口新增了一个 sendNow 方法。如果您的应用程序或包手动实现了该接口,您需要将新的 sendNow 方法添加到您的实现中:

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

Packages

将服务提供者发布到应用程序

影响可能性:非常低

如果您编写了一个 Laravel 包,手动将服务提供者发布到应用程序的 app/Providers 目录,并手动修改应用程序的 config/app.php 配置文件来注册服务提供者,您应该更新您的包以使用新的 ServiceProvider::addProviderToBootstrapFile 方法。

addProviderToBootstrapFile 方法将自动把您发布的服务提供者添加到应用程序的 bootstrap/providers.php 文件中,因为在新的 Laravel 11 应用程序中,config/app.php 配置文件中不再存在 providers 数组。

use Illuminate\Support\ServiceProvider;

ServiceProvider::addProviderToBootstrapFile(Provider::class);

队列

BatchRepository 接口

影响可能性:非常低

Illuminate\Bus\BatchRepository 接口现在新增了一个 rollBack 方法。如果您在自己的包或应用程序中实现了此接口,您应将该方法添加到您的实现中:

public function rollBack();

数据库事务中的同步作业

影响可能性:非常低

之前,使用同步队列驱动(sync)的作业会立即执行,无论 queue 连接的 after_commit 配置选项是否设置为 true,或者作业是否调用了 afterCommit 方法。

在 Laravel 11 中,同步队列作业现在会遵循队列连接或作业的 “提交后”(after commit)配置。

速率限制

每秒限流

影响的可能性:中

Laravel 11 支持每秒速率限制,而不仅限于每分钟的粒度。对于这个变化,您需要注意以下一些潜在的破坏性更改。

GlobalLimit 类构造函数 现在接受秒数而不是分钟数。此类没有文档,通常不会被您的应用程序使用:

new GlobalLimit($attempts, 2 * 60);

Limit 类构造函数 现在接受秒数而不是分钟数。该类的所有文档化用法都限于静态构造函数,如 Limit::perMinuteLimit::perSecond。然而,如果您手动实例化此类,您应该更新您的应用程序,向类构造函数提供秒数:

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

Limit 类的 decayMinutes 属性 已更名为 decaySeconds,并且现在包含秒数而不是分钟数。

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

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 不再自动加载来自其自身迁移目录的迁移文件。相反,您需要运行以下命令将 Cashier Stripe 的迁移文件发布到您的应用程序中:

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

请查看完整的 Cashier Stripe 升级指南 以了解更多破坏性更改。

Spark(Stripe)

更新 Spark Stripe

影响可能性:高

Laravel 11 不再支持 Laravel Spark Stripe 4.x。因此,您需要将应用程序中的 Laravel Spark Stripe 依赖项更新为 ^5.0,在 composer.json 文件中进行更改。

Spark Stripe 5.0 不再自动加载来自其自身迁移目录的迁移文件。相反,您需要运行以下命令,将 Spark Stripe 的迁移文件发布到您的应用程序:

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

请查阅完整的 Spark Stripe 升级指南,以了解更多破坏性更改。

Passport

更新 Passport

影响可能性:高

Laravel 11 不再支持 Laravel Passport 11.x。因此,您需要将应用程序中的 Laravel Passport 依赖项更新为 ^12.0,在 composer.json 文件中进行更改。

Passport 12.0 不再自动加载来自其自身迁移目录的迁移文件。相反,您需要运行以下命令,将 Passport 的迁移文件发布到您的应用程序:

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

此外,密码授权类型(password grant)默认被禁用。如果需要启用它,可以在应用程序的 AppServiceProviderboot 方法中调用 enablePasswordGrant 方法:

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

Sanctum

更新 Sanctum

影响可能性:高

Laravel 11 不再支持 Laravel Sanctum 3.x。因此,您需要将应用程序中的 Laravel Sanctum 依赖项更新为 ^4.0,在 composer.json 文件中进行更改。

Sanctum 4.0 不再自动加载来自其自身迁移目录的迁移文件。相反,您需要运行以下命令,将 Sanctum 的迁移文件发布到您的应用程序:

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。因此,您需要将应用程序中的 Laravel Telescope 依赖项更新为 ^5.0,在 composer.json 文件中进行更改。

Telescope 5.0 不再自动加载来自其自身迁移目录的迁移文件。相反,您需要运行以下命令,将 Telescope 的迁移文件发布到您的应用程序:

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

Spatie Once Package

影响可能性:中

Laravel 11 现在提供了自己的 once 函数,确保给定的闭包只执行一次。因此,如果您的应用程序依赖于 spatie/once 包,您应将其从应用程序的 composer.json 文件中移除,以避免冲突。

Miscellaneous

我们还鼓励您查看 laravel/laravel GitHub 仓库 中的更改。虽然这些更改并非必需,但您可能希望将这些文件与应用程序保持同步。部分更改将在本升级指南中提及,但其它更改,如配置文件或注释的更改,则不会。您可以轻松使用 GitHub 比较工具 查看这些更改,并选择对您重要的更新。