升级指南
重要更新概览
影响较大
- 缓存有效期单位调整为秒
- 缓存锁安全优化
- 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
类及其扩展类的 put
、putMany
、add
、remember
和 setDefaultCacheTime
方法,以及每个缓存存储器的 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
类的 put
、putMany
和 add
方法的 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();
Repository
和 Store
契约
影响级别:极低
为了完全符合 PSR-16 标准,Illuminate\Contracts\Cache\Repository
契约的 put
和 forever
方法、以及 Illuminate\Contracts\Cache\Store
契约的 put
、putMany
和 forever
方法的返回值已经由 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 自定义中间模型
如果你定义了一个多对多关联并使用了自定义的中间模型,同时这个中间模型还有一个自增的主键,那么你需要确保自定义的中间模型类定义了一个被设置为 true
的 incrementing
属性:
/**
* 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
关联关系的 getForeignKey
和 getQualifiedForeignKey
方法已经分别被重命名为 getForeignKeyName
和 getQualifiedForeignKeyName
,从而和 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
类的 send
、sendNow
、queue
、later
和 fill
方法被调整为接受 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
契约中新增了 isReleased
、 hasFailed
和 markAsFailed
方法,如果你实现了这个接口,需要添加这些方法的实现。
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/UrlGenerator
的 cachedSchema
属性
影响级别:极低
Illuminate/Routing/UrlGenerator
的 $cachedSchema
属性名(在 Laravel 5.7 中废弃)被调整为 $cachedScheme
。
会话(Session)
StartSession
中间件
影响级别:极低
会话持久化逻辑从 terminate()
方法转移到 handle()
方法中,如果你重写了其中任意一个方法,需要更新它们来适应这个调整。
Support
优先使用字符串和数组类而不是辅助函数
影响级别:中等
所有的 array_*
和 str_*
全局辅助函数都被废弃,需要使用 Illuminate\Support\Arr
和 Illuminate\Support\Str
类中提供的方法来替代相应的功能。
这个调整的影响级别被标记为中等,因为这些辅助函数被转移到新的 laravel/helpers 扩展包中,以便更好地向后兼容。
延迟的服务提供者
影响级别:中等
服务提供者中的 defer
布尔属性过去用于标识该提供者是否延迟的这一特性已经被废弃。现在如果要将服务提供者标记为延迟的需要通过实现 Illuminate\Contracts\Support\DeferrableProvider
契约来完成。
测试
PHPUnit 8
影响级别:可选
默认情况下,Laravel 5.8 使用 PHPUnit 7,不过,你可以选择升级到 PHPUnit 8,此时,对应的 PHP 版本需要高于或等于 7.2,更多细节可以阅读 PHPUnit 8 版本声明。
setUp
个 tearDown
方法现在要求返回 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 中的 parseTable
、getQueryColumn
和 requireParameterCount
方法可见性从 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 比较工具 轻松查看变更以便选择那些对你而言更为重要的更新。
No Comments