Laravel 升级索引

重大影响的改变

中等影响的改变

从 5.7 升级到 5.8.0

预计升级耗时:1小时

注:我们试图记录每一个可能发生的变化。因为大部分破坏性的变化在框架的内部,这些更改仅有一部分的更改可能影响你的应用。

更新依赖

composer.json 文件中将 laravel/framework 更新为 5.8.*

接下来,检查应用程序中已安装的第三方包是否支持 Laravel 5.8,并检查已安装的版本是否正确。

应用契约

environment 方法

影响可能性:非常低

Illuminate/Contracts/Foundation/Applicationenvironment 方法的签名已修改。如果在您的应用程序中重写了这个方法,您应该更新此方法的签名:

/**
 * Get or check the current application environment.
 *
 * @param  string|array  $environments
 * @return string|bool
 */
public function environment(...$environments);

新添加的方法

影响可能性:非常低

新加方法 bootstrapPath, configPath, databasePath, environmentPath, resourcePath, storagePath, resolveProvider, bootstrapWith, configurationIsCached, detectEnvironment, environmentFile, environmentFilePath, getCachedConfigPath, getCachedRoutesPath, getLocale, getNamespace, getProviders, hasBeenBootstrapped, loadDeferredProviders, loadEnvironmentFrom, routesAreCached, setLocale, shouldSkipMiddleware 这个 terminate 方法 将会添加到 Illuminate/Contracts/Foundation/Application 契约中.

如果你实现了这个接口,你应该将这些方法添加到实现类中。

认证

重置密码通知路由参数

影响可能性:非常低

当用户点击重置密码链接时,Laravel 使用 route 助手生成 URL ,以创建指向以 password.reset 命名的路由,当使用 Laravel 5.7 的时候,token 将会被传递到不带显式名称的 route 助手,比如:

route('password.reset', $token);

当你使用 Laravel 5.8 时,token 作为显式参数传递给 route 助手:

route('password.reset', ['token' => $token]);

因此,如果你要定义自己的 password.reset 路由,则它的 uri 中一定要包含一个 token 参数。

重新定义默认密码的长度

影响可能性:非常低

选择或重置密码时所需的密码长度 改为至少需要8个字符.

缓存

TTL单位为改秒

影响可能性:非常高

为了在存储数据时允许更精细的到期时间,缓存数据的生存时间从分改为秒。 Illuminate\Cache\Repository 类和它的扩展类的 putputManyaddremembersetDefaultCacheTime 方法,以及所有缓存存储器的 put 方法都完成了此更新。详情请看 相关的 PR

如果要向这些方法中的任何一个传递整数,请更新代码以确保保留在缓存中的数据传递的数值是秒。另外,你可以传递一个 DateTime 实例指示数据何时到期:

// Laravel 5.7 - Store item for 30 minutes...
Cache::put('foo', 'bar', 30);

// Laravel 5.8 - Store item for 30 seconds...
Cache::put('foo', 'bar', 30);

// Laravel 5.7 / 5.8 - Store item for 30 seconds...
Cache::put('foo', 'bar', now()->addSeconds(30));

{提示} 此更改使 Laravel 缓存系统完全符合 PSR-16 缓存库标准 。

遵循 PSR-16

影响可能性:中等

除了以上返回值有变化之外,本次升级还更新了 Illuminate\Cache\Repository 类中的 putputManyadd 方法的 TTL 参数,使之更符合 PSR-16 规范。新特性提供了一个默认的 null ,所以如果不指定 TTL 值,那么缓存将会永久存储不会过期。此外,如果缓存项的 TTL 为 0 或者更小,那么将会被清除。参阅 相关的 PR 获取更多信息。

KeyWritten 事件基于这些变动 也进行了更新

锁安全性改善

影响可能性:高

在 Laravel 5.7 以及 Laravel 更早的版本的中,一些缓存驱动提供的 “原子锁” 特性,可能由于一些意外行为导致锁被提前释放。

例如: 客户端 A 获取了一个 10 秒过期的锁 foo。客户端 A 实际上需要耗费 20 秒来完成它的任务。在客户端 A 任务执行期间,锁被缓存系统自动释放。之后 客户端 B 获取到锁 foo。最终 客户端 A 完成了它的任务并释放掉锁 foo,但是无意中释放了 客户端 B 所持有的锁。这时候 客户端 C 又可以获取到锁。

为了缓解这种情况,现在使用嵌入的「范围令牌」生成锁,这样可以确保在正常情况下,只有锁的持有者才能释放锁。

如果你正在使用 Cache::lock()->get(Closure) 方法使用锁,则不需要进行任何更改:

Cache::lock('foo', 10)->get(function () {
    // Lock will be released safely automatically...
});

但是,如果要手动调用, Cache::lock()->release() ,则必须更新代码以维护锁的实例。然后,在完成任务后,可以在同一个锁实例上调用 release 方法。例如:

if (($lock = Cache::lock('foo', 10))->get()) {
    // Perform task...

    $lock->release();
}

有时,您可能希望在一个进程中获取锁定并在另一个进程中释放它。例如,您可以在 Web 请求期间获取锁定,并希望在该请求触发的排队作业结束时释放锁定。在这种情况下,您应该将锁定的作用域「owner token」传递给排队的作业,以便作业可以使用给定的令牌重新实例化锁:

// Within Controller...
$podcast = Podcast::find(1);

if (($lock = Cache::lock('foo', 120))->get()) {
    ProcessPodcast::dispatch($podcast, $lock->owner());
}

// Within ProcessPodcast Job...
Cache::restoreLock('foo', $this->owner)->release();

如果您想在不尊重其当前所有者的情况下释放锁定,您可以使用以下 forceRelease 方法:

Cache::lock('foo')->forceRelease();

The RepositoryStore 契约

影响可能性:非常低

为了完全符合 PSR-16 的要求,Illuminate\Contracts\Cache\Repository 契约的 putforever 方法的返回值以及 Illuminate\Contracts\Cache\Store 契约的 put, putManyforever 方法 已更改voidbool

集合

add 方法

影响可能性:非常低

add 方法 已被移动 从 Eloquent 集合类 到集合的基类. 如果您继承 Illuminate\Support\Collection 类中的 add 方法, 请使用它的基类:

public function add($item);

firstWhere 方法

影响可能性:非常低

firstWhere 方法参数 已更改 匹配 where 方法的签名。如果要重写此方法,则应更新方法的参数来匹配其父级:

/**
 * Get the first item by the given key value pair.
 *
 * @param  string  $key
 * @param  mixed  $operator
 * @param  mixed  $value
 * @return mixed
 */
public function firstWhere($key, $operator = null, $value = null);

终端

Kernel 契约

影响可能性:非常低

terminate 方法 已经添加到 Illuminate/Contracts/Console/Kernel 契约中。如果你实现了这个接口,则应该将这个方法添加到实现类中。

容器

容器的生成 & 标签服务

影响可能性:中等

容器的 tagged 方法使用 PHP 生成器通过给定的标记惰性地实例化服务。由于这种改变,tagged 方法返回 iterable 类型,而不是 数组。如果你这个方法使用了类型提示的返回值,则应确保将类型提示也更改为 iterable 类型。

另外,不能再通过数组偏移值直接访问标记服务 ,比如 $container->tagged('foo')[0]

resolve 方法

影响可能性:非常低

resolve 方法 接收一个新布尔参数,该参数指示事件在对象实例化期间是否应触发 / 执行(解析回调)。如果你重写了这个方法,你必须更新方法签名以匹配父方法。

addContextualBinding 方法

影响可能性:非常低

Illuminate\Contracts\Container\Container 契约增加了 addContextualBinding 方法。如果要实现此接口,则应将此方法加到你的实现中。

tagged 方法

影响可能性:非常低

tagged 方法现在 改为 返回 iterable 类型而不是 array 类型。如果你的代码参数有类型提示,找到所有 tagged 方法提示 array 类型的地方,将类型提示改为 iterable 类型。

flush 方法

Illuminate\Contracts\Container\Container 契约增加了 flush 方法。如果要实现此接口,则应将此方法加到你的实现中。

数据库

未被引号包围的 MySQL JSON 值

影响可能性:低

在使用 MySQL 和 MariaDB 的时候,Query 构造器返回的 JSON 值将不会使用引号包围。其他数据库将和这里的行为保持一致:

$value = DB::table('users')->value('options->language');

dump($value);

// Laravel 5.7...
'"en"'

// Laravel 5.8...
'en'

结果为,不再支持或不再需要 ->> 操作符了。

SQLite

影响可能性:中等

从 Laravel 5.8 开始, 最早版本 SQLite 支持 一直到 SQLite 3.7.11。如果你使用的是更早之前的 SQLite 版本,你应该升级 (推荐升级到 SQLite 3.8.8+)。

迁移 & bigIncrements

影响可能性:无

从 Laravel 5.8开始, 迁移使用 bigIncrements 做为 ID 字段的默认方法. 以前, ID 字段使用是 increments 方法.

这个改变不会影响到目前的代码; 但是,外键字段的类型要与主键的类型保持一致。一个使用 increments 方法是不能创建一个使用 bigIncrements 方法外键约束的.

Eloquent

模型命名中的不规则复数结尾

影响可能性:中等

从 Laravel 5.8 起,含有不规则复数形式结尾的复合名称模型命名 现在可以正确的进行复数化.

// Laravel 5.7...
App\Feedback.php -> feedback (correctly pluralized)
App\UserFeedback.php -> user_feedbacks (incorrectly pluralized)

// Laravel 5.8
App\Feedback.php -> feedback (correctly pluralized)
App\UserFeedback.php -> user_feedback (correctly pluralized)

如果你的模型名称没有正确的使用复数名称,你在模型中定义 $table 属性之后还是可以继续使用它的:

/**
 * The table associated with the model.
 *
 * @var string
 */
protected $table = 'user_feedbacks';

带有递增 ID 的自定义中继模型

如果你用一个自定义的中继模型定义了多对多的关系,而且这个中继模型拥有一个自增的主键,你应当确保这个自定义中继模型类中定义了一个 incrementing 属性其值为 true

/**
 * Indicates if the IDs are auto-incrementing.
 *
 * @var bool
 */
public $incrementing = true;

loadCount 方法

影响可能性:低

基础类 Illuminate\Database\Eloquent\Model 中添加了 loadCount 方法。如果你的应用中也定义了 loadCount 方法,可能会和 Eloquent 中的相冲突。

originalIsEquivalent 方法

影响可能性:非常低

Illuminate\Database\Eloquent\Concerns\HasAttributes trait 中的 originalIsEquivalent 成员方法从 protected 改变为 public 。

deleted_at 属性的自动软删除转换

影响可能性:低

当你的 Eloquent 模型使用了 Illuminate\Database\Eloquent\SoftDeletes trait 时 deleted_at 成员属性 现将会自动转换 成为一个 Carbon 实例。你可以重写这个行为,通过为该成员属性编写你的自定义 accessor 或者手动将它添加到 casts 属性中:

protected $casts = ['deleted_at' => 'string'];

BelongsTo 的 getForeignKey & getOwnerKey 方法

影响可能性:低

BelongsTo 关联关系中的 getForeignKeygetQualifiedForeignKey 方法已分别重命名为 getForeignKeyNamegetQualifiedForeignKeyName,使得方法名和在 Laravel 提供的其他关联关系中保持一致。

环境变量的解析

影响可能性:高

phpdotenv 包用于 .env 文件解析已经发布了新版,将会影响到 env 全局方法的返回结果. 具体来说, # 未加引号的将被视为注释:

以前的做法

ENV_VALUE=foo#bar

env('ENV_VALUE'); // foo#bar

现在的做法

ENV_VALUE=foo#bar
env('ENV_VALUE'); // foo

对于以前的做法你需要使用引号将其包起来:

ENV_VALUE="foo#bar"

env('ENV_VALUE'); // foo#bar

更多信息, 请点击此链接 phpdotenv 升级说明.

事件

fire 方法

影响可能性:低

Illuminate/Events/Dispatcher 类中的 fire 方法 (在 Larevel 5.4 中不赞成使用) 已经被 移除 了。 你应当使用它的替代方法 dispatch

异常处理器

ExceptionHandler 契约

影响可能性:低

Illuminate\Contracts\Debug\ExceptionHandler 契约中新增了 shouldReport 方法。 现在当你实现异常处理器的接口时,你需要同时实现此方法。

renderHttpException 方法

影响可能性:低

Illuminate\Foundation\Exceptions\Handler 类中 renderHttpException 方法的签名 有改动 。现在如果你在异常处理器中重写此方法,应当修改方法的签名以和其父类保持一致:

/**
 * Render the given HttpException.
 *
 * @param  \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface  $e
 * @return \Symfony\Component\HttpFoundation\Response
 */
protected function renderHttpException(HttpExceptionInterface $e);

Mail

Markdown文件目录有改变

影响可能性:高

如果你使用此命令 vendor:publish 生成邮件的Markdown服务, 你需要将此目录 /resources/views/vendor/mail/markdown 改为 text

此外, markdownComponentPaths 方法 已经重命名textComponentPaths。 如果你重写了此方法则需要更新。

签名方法已经改动到 PendingMail 类中

影响可能性:非常低

Illuminate\Mail\PendingMail 类中的 send, sendNow, queue, laterfill 方法 已被更改 为需接收一个 Illuminate\Contracts\Mail\Mailable 实例作为参数,而不是 Illuminate\Mail\Mailable 实例。如果你要重写其中的方法,你需要更新其形参,和其父类保持一致。

队列

Pheanstalk 4.0

影响可能性:中

Laravel 5.8 提供了支持 ~4.0 发布版本的 Pheanstalk 队列。如果你正在应用中使用 Pheanstalk 库,请通过 Composer 升级你的库到 ~4.0 发布版本。

Job 契约

影响可能性:非常低

isReleasedhasFailedmarkAsFailed 方法 已被加入到 Illuminate\Contracts\Queue\Job 契约中 。如果你正在实现这个接口,你应该添加这些方法到你的实现代码中。

Job::failed & FailingJob

影响可能性:非常低

在 Laravel 5.7 中,当一个队列任务失败后,队列 worker 将执行 FailingJob::handle 方法。在 Laravel 5.8 中,FailingJob 类中的逻辑已被迁移到了 fail 方法中,该方法就定义在这个任务类中。正因如此, fail 方法被纳入了 Illuminate\Contracts\Queue\Job 契约。

Illuminate\Queue\Jobs\Job 基类包含了 fail 的实现,在常规的应用里不需要改任何代码。然而,如果你正在搭建自定义的队列驱动,起了一个任务类,该任务类 没有 继承由 Laravel 提供的任务基类,你应该在你自定义的任务类中手动实现 fail 方法。作为实现的参考,你可以查阅 Laravel 的任务基类。

这个改变允许定制队列驱动,从而在对任务删除过程获得更多的控制。

Redis Blocking Pop

影响可能性:非常低

现在使用 Redis 队列驱动的 「blocking pop」特性是安全的。在之前,如果 Redis 服务或者 worker 掉线的同时取出任务,可能造成队列中的任务丢失(小概率事件)。 为了让 blocking pops 变得安全,将给每一个 Laravel 队列创建一个新的带有 :notify 后缀的 Redis list 。

请求

TransformsRequest 中间件

影响可能性:低

现在,当请求输入是一个数组时, Illuminate\Foundation\Http\Middleware\TransformsRequest 中间件的 transform 方法将接收到「全限定」 请求输入的 key :

'employee' => [
    'name' => 'Taylor Otwell',
],

/**
 * Transform the given value.
 *
 * @param  string  $key
 * @param  mixed  $value
 * @return mixed
 */
protected function transform($key, $value)
{
    dump($key); // 'employee.name' (Laravel 5.8)
    dump($key); // 'name' (Laravel 5.7)
}

路由

UrlGenerator 契约

影响可能性:非常低

previous 方法 已经添加到 Illuminate\Contracts\Routing\UrlGenerator contract 中。如果要调用这个接口,你应该将这个方法添加到你的实现中。

Illuminate/Routing/UrlGenerator 中的 cachedSchema 特性

影响可能性:非常低

Illuminate/Routing/UrlGenerator 中的 $cachedSchema 属性 (在 Laravel 5.7 中已被弃用) 已更改为 $cachedScheme

Sessions

StartSession 中间件

影响可能性:非常低

Session 的持久性逻辑已 从 terminate() 方法移动到 handle() 方法。 如果你要重写其中的方法, 则应该更新它们以反映这些更改。

Support

优先使用字符串和数组类而不是辅助函数

影响可能性:中等

所有的 array_* and str_* 全局辅助函数 都被废弃。你需要直接使用 Illuminate\Support\ArrIlluminate\Support\Str 提供的方法。

这个调整的影响被标记为中等,因为这些辅助函数被转移到新的 laravel/helpers 扩展包中,以便更好地向后兼容。

延迟的服务提供者

影响可能性:中等

服务提供程序的用于指示是否延迟提供程序的 defer 布尔属性已经被废弃。现在如果要将服务提供者标记为延迟的需要通过实现 Illuminate\Contracts\Support\DeferrableProvider 契约来完成。

只读 env 辅助函数

影响可能性:低

之前你可以使用 env 辅助函数来动态改变值。但是从 Laravel 5.8开始,将不生效。 可以考虑使用 config 辅助函数来处理。

之前的做法:

dump(env('APP_ENV')); // local

putenv('APP_ENV=staging');

dump(env('APP_ENV')); // staging

现在的做法:

dump(env('APP_ENV')); // local

putenv('APP_ENV=staging');

dump(env('APP_ENV')); // local

测试

setUp & tearDown 方法

setUptearDown 方法现在需要返回一个空类型:

protected function setUp(): void
protected function tearDown(): void

PHPUnit 8

影响可能性:可选

默认情况下, Laravel 5.8 使用 PHPUnit 7.。不过, 你可以升级到 PHPUnit 8,但是这需要 PHP >= 7.2。更多细节请阅读 PHPUnit 8 版本声明

验证

Validator 契约

影响可能性:低

Illuminate\Contracts\Validation\Validator 中 新增了 validated 方法:

/**
 * Get the attributes and values that were validated.
 *
 * @return array
 */
public function validated();

如果你调用了这个接口,需要添加此方法的实现。

ValidatesAttributes 特性

影响可能性:非常低

Illuminate\Validation\Concerns\ValidatesAttributes 特性中的 parseTablegetQueryColumnrequireParameterCount 方法可见性从 protected 调整为了 public

DatabasePresenceVerifier

影响可能性:非常低

Illuminate\Validation\DatabasePresenceVerifier 类的 table 方法可见性从 protected 调整为了 public

Validator

影响可能性:非常低

Illuminate\Validation\Validator 类的 getPresenceVerifierFor 方法可见性从 protected 调整为了 public

邮箱验证

影响可能性:非常低

邮箱验证规则现在回检测邮箱地址是否兼容 RFC5630, 使验证逻辑和 SwiftMailer 保持一致。在 Laravel 5.7, email 规则只验证邮箱地址是否兼容 RFC822

因此 当使用 Laravel 5.8 时,之前认为无效的邮箱地址现在将被视为有效,如 (e.g hej@bär.se)。 通常,这被看做一个 bug 修复; 不过, 我们还是将其列到这里给你一个提醒。如果您遇到有关此更改的任何问题,请通知我们

视图

getData 方法

影响可能性:非常低

Illuminate\Contracts\View\View 契约中新增了 getData 方法。如果你调用了这个接口, 则需要添加该方法的实现。

通知

Nexmo / Slack 通知频道

影响可能性:高

Nexmo 和 Slack 通知频道已经被提前到官方扩展中。要在自己的应用中使用这些频道,需要安装以下扩展包:

composer require laravel/nexmo-notification-channel
composer require laravel/slack-notification-channel

其他

我们还鼓励你查看 laravel/laravel 代码仓库的更新日志。尽管其中的很多更新不是必须的,但是你可以将你的应用中的这些文件与代码仓库保持同步。其中一些更新已经在这篇升级指南中提到了,但是还有很多其他的小更新(如对配置文件或注释的更改)就不会列出。你可以通过 GitHub 比较工具 查看哪些更新对你而言更加重要。