升级指南
高影响变化
中影响变化
- Belongs To Many
firstOrNew
,firstOrCreate
, andupdateOrCreate
方法 - Custom Casts &
null
- Default HTTP Client Timeout
- PHP Return Types
- Postgres "Schema" Configuration
- The
assertDeleted
Method - The
lang
Directory - The
password
Rule - The
when
/unless
Methods - Unvalidated Array Keys
从 8.x 升级到 9.0
预计升级时间: 30 分钟
技巧:我们应该试图记录每个可能的重大改变. 由于一些破坏性的变更位于框架的模糊部分,因此这些更改只有一部分可能会实际影响你的应用程序. 想要节省时间? 你可以看 Laravel Shift 来帮助你的应用自动化升级。
更新依赖
影响的可能性: 高
要求 PHP 8.0.2
Laravel 现在 需要 PHP 8.0.2 or 更高。
Composer 依赖
你应该在你应用程序的 composer.json
文件中更新依赖包的版本
laravel/framework
至^9.0
nunomaduro/collision
至^6.1
另外,请在 composer.json
文件中用 "spatie/laravel-ignition": "^1.0"
替换掉 facade/ignition
以下官方包的新版本已经支持 Laravel 9.x 。如有需要,你应该在升级前阅读它们各自的升级指南:
- Vonage Notification Channel (v3.0) (Replaces Nexmo)
最后,检查应用程序使用的任何其他第三方包,并验证是否使用了正确的支持 Laravel 9 的版本。
PHP 返回类型
PHP 开始过渡到要求在 PHP 方法(如 offsetGet
、offsetSet
等)上定义返回类型。有鉴于此,Laravel 9 在其代码库中实现了这些返回类型。通常,这应该不会影响用户编写的代码;但是,如果您通过扩展 Laravel 的 核心类来重写这些方法之一,则需要将这些返回类型添加到您自己的应用程序或包代码中:
count(): int
getIterator(): Traversable
getSize(): int
jsonSerialize(): array
offsetExists($key): bool
offsetGet($key): mixed
offsetSet($key, $value): void
offsetUnset($key): void
此外,返回类型被添加到实现 PHP 的 SessionHandlerInterface
接口的方法中。同样,这个更改不太可能影响您自己的应用程序或包代码:
open($savePath, $sessionName): bool
close(): bool
read($sessionId): string|false
write($sessionId, $data): bool
destroy($sessionId): bool
gc($lifetime): int
Application
Application
契约
影响程度:低
Illuminate\Contracts\Foundation\Application
接口的 storagePath
方法已更新为接受 $path
参数。如果要实现此接口,则应相应地更新实现代码:
public function storagePath($path = '');
同样,Illuminate\Foundation\Application
类的 langPath
方法已更新为接受 $path
参数:
public function langPath($path = '');
异常处理程序ignore
方法
影响的可能性:低
异常处理程序的 ignore
方法现在是 public
而不是 protected
。此方法不包含在默认应用程序框架中;但是,如果您手动定义了此方法,则应将其可见性更新为“public”:
public function ignore(string $class);
Blade
惰性集合和 $loop
变量
影响的可能性:低
当在 Blade 模板中迭代 LazyCollection
实例时,$loop
变量不再可用,因为访问该变量会导致整个 LazyCollection
被加载到内存中,因此在这种情况下使用惰性集合是毫无意义的。
集合
Enumerable
契约
影响的可能性:低
Illuminate\Support\Enumerable
合约现在定义了 sole
方法。如果您手动实现此接口,则应更新您的实现以显示此新方法:
public function sole($key = null, $operator = null, $value = null);
reduceWithKeys
方法
reduceWithKeys
方法已被删除,因为 reduce
方法提供了相同的功能。你 可以简单地更新你的代码来调用 reduce
而不是 reduceWithKeys
。
reduceMany
方法
reduceMany
方法已重命名为 reduceSpread
,以便与其他类似方法的命名保持一致。
容器
Container
契约
影响的可能性:非常低
Illuminate\Contracts\Container\Container
契约有两个方法定义:scoped
和 scopedIf
。如果您手动实施此契约,您应该更新您的实施以显示这些新方法。
ContextualBindingBuilder
契约
影响的可能性:非常低
Illuminate\Contracts\Container\ContextualBindingBuilder
契约现在定义了 giveConfig
方法。如果您手动实现此接口,则应更新您的实现以显示此新方法:
public function giveConfig($key, $default = null);
数据库
Postgres "Schema" 配置选项
影响程度:中
在 config/database.php
配置文件中用配置 Postgres 连接搜索路径的 schema
配置选项应重命名为 search_path
。
Schema Builder registerCustomDoctrineType
方法
影响程度:低
registerCustomDoctrineType
方法已从 Illuminate\Database\Schema\Builder
类中删除。您可以在 DB
上使用 registerDoctrineType
方法,或者在 config/database.php
配置文件中注册自定义的 Doctrine 类型。
Eloquent
自定义强制转换和 null
影响程度:中
在 Laravel 的先前版本中,如果将强制转换属性设置为 null
,则不会调用自定义强制转换类的 set
方法。但是,此行为与 Laravel 文档不一致。在 Laravel 9.x 中,将调用 cast 类的 set
方法,并使用 null
作为提供的 $value
参数。因此,应确保自定义强制转换能够充分处理这个场景:
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param AddressModel $value
* @param array $attributes
* @return array
*/
public function set($model, $key, $value, $attributes)
{
if (! $value instanceof AddressModel) {
throw new InvalidArgumentException('The given value is not an Address instance.');
}
return [
'address_line_one' => $value->lineOne,
'address_line_two' => $value->lineTwo,
];
}
Belongs To Many 的 firstOrNew
、firstOrCreate
和 updateOrCreate
方法
影响程度:中
belongsToMany
关系的 firstOrNew
、firstOrCreate
和 updateOrCreate
方法都接受一个属性数组作为其第一个参数。在 Laravel 的先前版本中,这个属性数组相当于现有记录的 pivot
中间表。
但是,这种行为是意料之外的,通常是不受欢迎的。相反,这些方法现在将属性数组与相关模型的表进行比较:
$user->roles()->updateOrCreate([
'name' => 'Administrator',
]);
此外,该 firstOrCreate
方法现在接受一个 $values
数组作为其第二个参数。 当创建相关模型时,如果该模型不存在,则该数组将与该方法的第一个参数 ($attributes
) 合并。此更改使此方法与其他关系类型提供的 firstOrCreate
方法一致:
$user->roles()->firstOrCreate([
'name' => 'Administrator',
], [
'created_by' => $user->id,
]);
touch
方法
影响的可能性:低
该 touch
方法现在接受要触摸的属性。如果你之前覆盖了这个方法,你应该更新你的方法签名来反映这个新参数:
public function touch($attribute = null);
Encryption
Encrypter 契约
影响的可能性:低
该 Illuminate\Contracts\Encryption\Encrypter
合约现在定义了一个方法 getKey
。如果您手动实现此接口,则应相应地更新您的实现:
public function getKey();
Facades
getFacadeAccessor
方法
影响的可能性:低
该 getFacadeAccessor
方法必须始终返回容器绑定键。在之前的 Laravel 版本中,这个方法可以返回一个对象实例;但是,不再支持此行为。如果您已经编写了自己的外观,则应确保此方法返回容器绑定字符串:
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return Example::class;
}
Filesystem
FILESYSTEM_DRIVER
环境变量
影响的可能性:低
FILESYSTEM_DRIVER
环境变量已重命名为 FILESYSTEM_DISK
以更准确地反映其用法。此更改仅影响应用程序框架; 但是,如果您愿意,欢迎您更新自己的应用程序的环境变量以反映此更改。
"Cloud" 磁盘
影响的可能性:低
cloud
磁盘配置选项已于 2020 年 11 月从默认应用程序骨架中删除。此更改仅影响应用程序骨架。如果您在应用程序中使用“云”磁盘,则应将此配置值保留在您自己的应用程序的框架中。
Flysystem 3.x
影响的可能性:高
Laravel 9.x 已从 Flysystem 1.x 迁移到 3.x。 在底层,Flysystem 支持 Storage
门面提供的所有文件操作方法。 鉴于此,您的应用程序中可能需要进行一些更改; 但是,我们已尝试使这种过渡尽可能无缝。
驱动器前置条件
在使用 S3、FTP 或 SFTP 驱动程序之前,您需要通过 Composer 包管理器安装相应的包:
- Amazon S3:
composer require -W league/flysystem-aws-s3-v3 "^3.0"
- FTP:
composer require league/flysystem-ftp "^3.0"
- SFTP:
composer require league/flysystem-sftp-v3 "^3.0"
覆盖现有文件
put
、write
、writeStream
等写操作现在默认覆盖现有文件。 如果您不想覆盖现有文件,则应在执行写入操作之前手动检查文件是否存在。
读取不存在的文件
在之前的 Laravel 版本中,尝试读取不存在的文件会抛出 Illuminate\Contracts\Filesystem\FileNotFoundException
,Laravel9 则会返回null
。
删除不存在的文件
尝试 删除
一个不存在的文件现在返回 true
。
缓存适配器
Flysystem 不再支持“缓存适配器”。 因此,它们已从 Laravel 中删除,并且任何相关配置(例如磁盘配置中的 cache
键)都可以删除。
自定义文件系统
对注册自定义文件系统驱动程序所需的步骤进行了轻微更改。 因此,如果您正在定义自己的自定义文件系统驱动程序,或者使用定义自定义驱动程序的包,您应该更新您的代码和依赖项。
例如,在 Laravel 8.x 中,自定义文件系统驱动程序可能会像这样注册:
use Illuminate\Support\Facades\Storage;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
Storage::extend('dropbox', function ($app, $config) {
$client = new DropboxClient(
$config['authorization_token']
);
return new Filesystem(new DropboxAdapter($client));
});
但是,在 Laravel 9.x 中,给 Storage::extend
方法的回调应该直接返回 Illuminate\Filesystem\FilesystemAdapter
的实例:
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\Filesystem;
use Spatie\Dropbox\Client as DropboxClient;
use Spatie\FlysystemDropbox\DropboxAdapter;
Storage::extend('dropbox', function ($app, $config) {
$adapter = new DropboxAdapter(new DropboxClient(
$config['authorization_token']
););
return new FilesystemAdapter(
new Filesystem($adapter, $config),
$adapter,
$config
);
});
Helpers
The data_get
Helper & Iterable Objects
data_get
助手和可迭代对象
以前,data_get
帮助器可用于检索数组和 Collection
实例上的嵌套数据;然而,这个助手现在可以检索所有可迭代对象的嵌套数据。
str
助手函数
影响的可能性:非常低
Laravel 9.x 现在包含一个全局 str
辅助函数。 如果你在你的应用程序中定义了一个全局的 str
助手,你应该重命名或删除它,这样它就不会与 Laravel 自己的 str
助手冲突。
when
/ unless
方法
影响的可能性:中等
你可能知道,when
和 unless
方法由整个框架中的各种类提供。 如果方法的第一个参数的布尔值评估为 true
或 false
,则这些方法可用于有条件地执行操作:
$collection->when(true, function ($collection) {
$collection->merge([1, 2, 3]);
});
因此,在 Laravel 的早期版本中,将闭包传递给 when
或 unless
方法意味着条件操作将始终执行,因为与闭包对象(或任何其他对象)的松散比较总是评估为 true
. 这通常会导致意想不到的结果,因为开发人员希望将闭包的结果用作确定条件操作是否执行的布尔值。
因此,在 Laravel 9.x 中,任何传递给 when
或 unless
方法的闭包都将被执行,并且闭包返回的值将被视为 when
和 unless
方法使用的布尔值:
$collection->when(function ($collection) {
// This closure is executed...
return false;
}, function ($collection) {
// Not executed since first closure returned "false"...
$collection->merge([1, 2, 3]);
});