升级指南


重要更新概览

影响较大

  • 缓存有效期单位调整为秒
  • 缓存锁安全优化
  • Markdown文件目录调整
  • Nexmo/Slack 通知频道

影响中等

  • 容器生成器 & 标签服务
  • SQLite 最低版本要求
  • 优先使用字符串和数组类而非辅助函数
  • 延迟服务提供者
  • PSR-16 规范
  • 模型名以不规则复数结尾
  • 通过自增 ID 自定义中间模型
  • Pheanstalk 4.0

预计升级时间:1个小时

注:本文档演示的是从 Laravel 5.7 升级到 5.8,我们将尽可能在文档中列出所有重大更新。

更新依赖

composer.json 文件中更新 laravel/framework 依赖到 5.8.*

当然,不要忘了检查应用所使用的第三方扩展包是否支持 Laravel 5.8,如果需要升级的话也要更新。

Application 契约

enviroment 方法

影响级别:极低

Illuminate/Contracts/Foundation/Application 契约的 environment 方法签名已经调整,如果你在应用中实现了这个契约,需要更新相应的方法签名:

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

新增的方法

影响级别:极低

Illuminate/Contracts/Foundation/Application 契约中新增bootstrapPath, configPath, databasePath, environmentPath, resourcePath, storagePath, resolveProvider, bootstrapWith, configurationIsCached, detectEnvironment, environmentFile, environmentFilePath, getCachedConfigPath, getCachedRoutesPath, getLocale, getNamespace, getProviders, hasBeenBootstrapped, loadDeferredProviders, loadEnvironmentFrom, routesAreCached, setLocale, shouldSkipMiddleware 以及 terminate 方法。

如果你碰巧实现了这个接口(概率极低),需要添加这些方法的实现。

认证

密码重置通知路由参数

影响级别:低

当用户通过请求链接重置密码时,Laravel 会使用辅助函数 route 传入命名路由 password.reset 生成对应的 URL。在 Laravel 5.7 中,令牌参数会直接传递到 route 函数,而没有显式的参数名:

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

在 Laravel 5.8 中,可以通过显式的参数名称来指定令牌参数,就像这样:

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

因此,如果你定义了自己的 password.reset 路由,需要确保其中包含了 {token} 参数。

新的默认密码长度

影响级别:低

在做密码字段必填校验时(注册或修改),密码长度被调整为至少八位

缓存

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 参数(Time-To-Live,缓存有效期)也被调整为更好地遵循 PSR-16 规范。这些方法支持有效期的默认值为 null,因此,当我们不指定 TTL 调用这些方法时,系统将会永久存储这些相应的缓存项。此外,如果缓存有效期设置为 0 或者更小的值,将会移除该缓存项。更多细节请查看相关的PR

最后,KeyWritten 事件也一并进行了更新

锁安全优化

影响级别:高

在 Laravel 5.7 及之前的版本中,某些缓存驱动提供了「原子锁」功能,但某些意想不到的行为有可能导致锁被提前释放。

例如,用户 A 获取了一个有效期为 10 秒的锁 foo,但实际花了 20 秒才完成任务,该锁会在用户 A 处理任务期间提前 10 秒被缓存系统自动释放。假设用户 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 请求期间获取了一个锁,然后想要在此次请求触发的队列任务最后释放锁,在这种场景中,你需要传递锁的「所有者令牌」到队列任务以便该任务可以使用给定的令牌重新实例化锁:

// 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();

RepositoryStore 契约

影响级别:极低

为了完全符合 PSR-16 标准,Illuminate\Contracts\Cache\Repository 契约的 putforever 方法、以及 Illuminate\Contracts\Cache\Store 契约的 putputManyforever 方法的返回值已经由 void 调整bool

集合

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 契约

影响级别:极低

Illuminate/Contracts/Console/Kernel 契约新增terminate 方法。如果你实现了这个接口,需要在实现这个方法。

容器

生成器 & 标签服务

影响级别:中等

容器的 tagged 方法现在使用了 PHP 生成器来懒实例化给定标签的服务,如果你没有使用所有打上标签的服务的话,这将带来一定的性能提升。

因为这个调整,tagged 方法现在返回的类型是 iterable 而不是 array,如果你在这个方法中对返回值做了类型提示,需要确保将类型提示调整为 iterable

此外,将不再能够通过数组偏移量直接访问打上标签的服务,例如 $container->tagged('foo')[0]

resolve 方法

影响级别:极低

resolve 方法现在接受一个新的布尔参数,用于标识在对象实例化期间是否触发/执行事件(解析回调)。如果你重写了这个方法,需要更新方法签名以匹配父方法。

addContextualBinding 方法

影响级别:极低

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

tagged 方法

影响级别:极低

前面已经提到,tagged 方法签名已经被调整,现在返回值类型是 iterable 而不是 array,如果你在代码中对其参数进行了类型提示,并通过数组获取返回值,则需要将其类型提示调整为 iterable

flush 方法

影响级别:极低

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

数据库

不带引号的 MySQL JSON 值

影响级别:低

查询构建器现在可以在使用 MySQL 和 MariaDB 时返回不带引号的 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+)。

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 自定义中间模型

如果你定义了一个多对多关联并使用了自定义的中间模型,同时这个中间模型还有一个自增的主键,那么你需要确保自定义的中间模型类定义了一个被设置为 trueincrementing 属性:

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

loadCount 方法

影响级别:低

Illuminate\Database\Eloquent\Model 类中新增了 loadCount 方法,如果你的应用中也定义了同名方法,将会与 Eloquent 的定义冲突。

originalIsEquivalent 方法

影响级别:极低

Illuminate\Database\Eloquent\Concerns\HasAttributes Trait 的 originalIsEquivalent 方法可见性从 protected 调整public

deleted_at 属性的自动软删除转化

影响级别:低

当你的 Eloquent 模型使用 Illuminate\Database\Eloquent\SoftDeletes Trait 时,deleted_at 属性现在会自动转化Carbon 实例,你可以通过编写该属性的自定义访问器或者手动将其添加到 casts 属性中来覆盖这一行为:

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

BelongsTo 的 getForeignKey 方法

影响级别:低

BelongsTo 关联关系的 getForeignKeygetQualifiedForeignKey 方法已经分别被重命名为 getForeignKeyNamegetQualifiedForeignKeyName,从而和 Laravel 提供的其它关联关系方法名保持一致。

事件

fire 方法

影响级别:低

Illuminate/Events/Dispatcher 类的 fire 方法(在 Laravel 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);

门面

门面服务解析

影响级别:低

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 提供了对对队列库 Pheanstalk 4.0 版本的支持,如果你在应用中使用了 Pheanstalk 库,请通过 Composer 将其升级到 ~4.0 版本。

Job 契约

影响级别:极低

Illuminate\Contracts\Queue\Job 契约中新增isReleasedhasFailedmarkAsFailed 方法,如果你实现了这个接口,需要添加这些方法的实现。

Job::failed & FailingJob

影响级别:极低

在 Laravel 5.7 中,当队列任务失败,队列进程会执行 FailingJob::handle 方法。在 Laravel 5.8 中,包含在 FailingJob 类中的这个逻辑被直接转移到队列类自身的 fail 方法中。正因如此,Illuminate\Contracts\Queue\Job 契约中新增了 fail 方法。

Illuminate\Queue\Jobs\Job 基类中包含了 fail 方法的实现,现有应用代码中不用做任何调整。不过,如果你构建了自定义的队列驱动,其中使用了没有继承自 Laravel 提供的队列任务基类的任务类,则需要在自定义任务类手动实现 fail 方法,这个时候,你可以参考 Laravel 任务基类中的实现。

这一调整允许自定义队列驱动对队列任务删除处理有更多控制权。

Redis Blocking Pop

影响级别:极低

使用 Redis 队列驱动的「blocking pop」特性现在已经安全了,在此之前,如果在获取任务的时候的同时,Redis 服务器或队列进程挂掉,有小概率会造成队列任务丢失。为了让「blocking pop」可以安全使用,会为每个 Laravel 队列创建一个以 :notify 开头的 Redis 列表。

请求

TransformsRequest 中间件

影响级别:低

当输入是数组时,Illuminate\Foundation\Http\Middleware\TransformsRequest 中间件的 transform 方法现在会接受完全限定的请求输入键:

'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 契约

影响级别:极低

Illuminate\Contracts\Routing\UrlGenerator 契约中新增previous 方法,如果你实现了这个接口,则需要新增该方法的实现。

Illuminate/Routing/UrlGeneratorcachedSchema 属性

影响级别:极低

Illuminate/Routing/UrlGenerator$cachedSchema 属性名(在 Laravel 5.7 中废弃)被调整为 $cachedScheme

会话(Session)

StartSession 中间件

影响级别:极低

会话持久化逻辑从 terminate() 方法转移handle() 方法中,如果你重写了其中任意一个方法,需要更新它们来适应这个调整。

Support

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

影响级别:中等

所有的 array_*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 类型:

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

验证

Validator 契约

影响级别:极低

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

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

如果你是实现了这个接口,需要添加该方法的实现。

ValidatesAttributes Trait

影响级别:极低

Illuminate\Validation\Concerns\ValidatesAttributes Trait 中的 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 时,之前认为无效的邮箱地址可能现在是有效的,通常,这被看做是一个 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 比较工具 轻松查看变更以便选择那些对你而言更为重要的更新。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 新版特性

>> 下一篇: 贡献指南