升级指南

高影响的改变

中等影响的改变

从 Laravel 5.7 更新到 5.8

预计升级时间:1 小时

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

更新依赖

composer.json 中,将 laravel/framework 依赖项更新为 5.8.*

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

应用契约

environment 方法

影响可能性:非常低

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

  1. /**
  2. * 获取或检查当前应用程序的环境
  3. *
  4. * @param string|array $environments
  5. * @return string|bool
  6. */
  7. 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 助手,比如:

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

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

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

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

默认密码长度改变

影响可能性:低

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

缓存

TTL 以秒为单位

影响可能性:非常高

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

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

  1. // Laravel 5.7 - 存储数据30分钟
  2. Cache::put('foo', 'bar', 30);
  3. // Laravel 5.8 - 存储数据30秒
  4. Cache::put('foo', 'bar', 30);
  5. // Laravel 5.7 / 5.8 - 存储数据30秒
  6. 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) 方法使用锁,则不需要进行任何更改:

  1. Cache::lock('foo', 10)->get(function () {
  2. // 锁将会被安全的自动释放
  3. });

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

  1. if (($lock = Cache::lock('foo', 10))->get()) {
  2. // 执行任务…
  3. $lock->release();
  4. }

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

  1. // 在控制器中…
  2. $podcast = Podcast::find(1);
  3. if (($lock = Cache::lock('foo', 120))->get()) {
  4. ProcessPodcast::dispatch($podcast, $lock->owner());
  5. }
  6. // 在进程广播队列中…
  7. Cache::restoreLock('foo', $this->owner)->release();

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

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

Repository 和 Store 契约

影响可能性:非常低

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

集合

firstWhere 方法

影响可能性:非常低

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

  1. /**
  2. * Get the first item by the given key value pair.
  3. *
  4. * @param string $key
  5. * @param mixed $operator
  6. * @param mixed $value
  7. * @return mixed
  8. */
  9. 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 值将不会使用引号包围。其他数据库将和这里的行为保持一致:

  1. $value = DB::table('users')->value('options->language');
  2. dump($value);
  3. // Laravel 5.7...
  4. '"en"'
  5. // Laravel 5.8...
  6. 'en'

因此,不再支持或不再需要->> 操作符了。

SQLite

影响可能性: 中等

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

Eloquent

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

影响可能性: 中等

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

  1. // Laravel 5.7...
  2. App\Feedback.php -> feedback (正确的复数形式)
  3. App\UserFeedback.php -> user_feedbacks (错误的复数形式)
  4. // Laravel 5.8
  5. App\Feedback.php -> feedback (正确的复数形式)
  6. App\UserFeedback.php -> user_feedback (正确的复数形式)

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

  1. /**
  2. * 与模型关联的数据表名称。
  3. *
  4. * @var string
  5. */
  6. protected $table = 'user_feedbacks';

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

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

  1. /**
  2. * 标识 ID 是否自增
  3. *
  4. * @var bool
  5. */
  6. 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 属性中:

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

BelongsTo 的 getForeignKey 方法

影响可能性:低

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

事件

fire 方法

影响可能性:低

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

异常处理器

ExceptionHandler 契约

影响可能性:低

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

renderHttpException 方法

影响可能性:低

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

  1. /**
  2. * 将给定的 Http 异常转换为 Http 响应。
  3. *
  4. * @参数 \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e
  5. * @返回 \Symfony\Component\HttpFoundation\Response
  6. */
  7. protected function renderHttpException(HttpExceptionInterface $e);

Facades

Facade 服务解析

影响可能性:低

getFacadeAccessor 方法现在可以 只返回代表服务容器标识的字符串 ,之前该方法会返回一个对象实例。

邮件

Markdown 文件路径更改

影响可能性:高

如果你已经使用 vendor:publish 命令发布了 Laravel 的 Markdown 邮件组件,你需要将 /resources/views/vendor/mail/markdown 路径重命名为 text

并且 markdownComponentPaths 方法 已被重命名textComponentPaths 。如果你要重写这个方法,你应该更新方法名,使之与其父类一致。

PendingMail 类中的方法形参改变

影响可能性:非常低

Illuminate\Mail\PendingMail 类中的 sendsendNowqueuelaterfill 方法 已被更改 为需接收一个 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 契约中 。如果你正在实现这个 interface ,你应该添加这些方法到你的实现代码中。

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 :

  1. 'employee' => [
  2. 'name' => 'Taylor Otwell',
  3. ],
  4. /**
  5. * 转换给定的值.
  6. *
  7. * @param string $key
  8. * @param mixed $value
  9. * @return mixed
  10. */
  11. protected function transform($key, $value)
  12. {
  13. dump($key); // 'employee.name' (Laravel 5.8)
  14. dump($key); // 'name' (Laravel 5.7)
  15. }

路由

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 契约来完成。

测试

PHPUnit 8

影响可能性: 可选

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

setUptearDown 方法现在要求返回void 类型:

  1. protected function setUp(): void
  2. protected function tearDown(): void

验证

Validator 契约

影响可能性: 非常低

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

  1. /**
  2. * 获取已验证的属性和值。
  3. *
  4. * @return array
  5. */
  6. 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 通知频道已经被提前到官方扩展中。要在自己的应用中使用这些频道,需要安装以下扩展包:

  1. composer require laravel/nexmo-notification-channel
  2. composer require laravel/slack-notification-channel

其他

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

本文章首发在 LearnKu.com 网站上。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接 我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。