预计升级时间:1 小时
注:我们试图记录每一个可能发生的变化。因为大部分破坏性的变化在框架的内部,这些更改仅有一部分的更改可能影响你的应用。
更新依赖
在 composer.json
中,将 laravel/framework
依赖项更新为 5.8.*
。
接下来,检查应用程序中已安装的第三方包是否支持 Laravel 5.8,并检查已安装的版本是否正确。
应用契约
environment 方法
影响可能性:非常低
Illuminate/Contracts/Foundation/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 参数。
默认密码长度改变
影响可能性:低
选择或重置密码时所需的密码长度 更改为至少八个字符 。
缓存
TTL 以秒为单位
影响可能性:非常高
为了在存储数据时允许更精细的到期时间,缓存数据的生存时间从分改为秒。 Illuminate\Cache\Repository
类和它的扩展类的 put
, putMany
, add
, remember
和 setDefaultCacheTime
方法,以及所有缓存存储器的 put
方法都完成了此更新。详情请看 相关的 PR 。
如果要向这些方法中的任何一个传递整数,请更新代码以确保保留在缓存中的数据传递的数值是秒。另外,你可以传递一个 DateTime
实例指示数据何时到期:
// Laravel 5.7 - 存储数据30分钟
Cache::put('foo', 'bar', 30);
// Laravel 5.8 - 存储数据30秒
Cache::put('foo', 'bar', 30);
// Laravel 5.7 / 5.8 - 存储数据30秒
Cache::put('foo', 'bar', now()->addSeconds(30));
{提示} 此更改使 Laravel 缓存系统完全符合 PSR-16缓存库标准 。
遵循 PSR-16
影响可能性:中等
除了以上返回值有变化之外,本次升级还更新了Illuminate\Cache\Repository
类中的 put
, putMany
和add
方法的 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 () {
// 锁将会被安全的自动释放
});
但是,如果要手动调用, Cache::lock()->release()
,则必须更新代码以维护锁的实例。然后,在完成任务后,可以在同一个锁实例上调用 release
方法。例如:
if ($lock = Cache::lock('foo', 10)->get()) {
// 执行任务…
$lock->release();
}
有时,您可能希望在一个进程中获取锁定并在另一个进程中释放它。例如,您可以在 Web 请求期间获取锁定,并希望在该请求触发的排队作业结束时释放锁定。在这种情况下,您应该将锁定的作用域「owner token」传递给排队的作业,以便作业可以使用给定的令牌重新实例化锁:
// 在控制器中…
$podcast = Podcast::find(1);
if ($lock = Cache::lock('foo', 120)->get()) {
ProcessPodcast::dispatch($podcast, $lock->owner());
}
// 在进程广播队列中…
Cache::restoreLock('foo', $this->owner)->release();
如果您想在不尊重其当前所有者的情况下释放锁定,您可以使用以下 forceRelease
方法:
Cache::lock('foo')->forceRelease();
影响可能性:非常低
为了完全符合 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 契约
影响可能性:非常低
terminate
方法 已经添加到 Illuminate/Contracts/Console/Kernel
契约中。如果你实现了这个接口,则应该将这个方法添加到实现类中。
容器
生成器 &标记服务
影响可能性:中等
容器的 tagged
方法使用PHP生成器通过给定的标记惰性地实例化服务。由于这种改变,tagged
方法返回 iterable
类型,而不是 数组
。如果你这个方法使用了类型提示的返回值,则应确保将类型提示也更改为 iterable
类型。
另外,不能再通过数组偏移值直接访问标记服务 ,比如 $container->tagged('foo')[0]
。
resolve 方法
影响可能性: 非常低
resolve
方法 接收一个新布尔参数,该参数指示事件在对象实例化期间是否应触发/执行(解析回调)。如果你重写了这个方法,你必须更新方法签名以匹配父方法。
影响可能性:非常低
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+)。
Eloquent
模型命名中的不规则复数结尾
影响可能性: 中等
从 Laravel 5.8 起,含有不规则复数形式结尾的复合名称模型命名 现在可以正确的进行复数化.
// Laravel 5.7...
App\Feedback.php -> feedback (正确的复数形式)
App\UserFeedback.php -> user_feedbacks (错误的复数形式)
// Laravel 5.8
App\Feedback.php -> feedback (正确的复数形式)
App\UserFeedback.php -> user_feedback (正确的复数形式)
如果你的模型名称没有正确的使用复数名称,你在模型中定义$table
属性之后还是可以继续使用它的:
/**
* 与模型关联的数据表名称。
*
* @var string
*/
protected $table = 'user_feedbacks';
带有递增 ID 的自定义中继模型
如果你用一个自定义的中继模型定义了多对多的关系,而且这个中继模型拥有一个自增的主键,你应当确保这个自定义中继模型类中定义了一个 incrementing
属性其值为true
:
/**
* 标识 ID 是否自增
*
* @var bool
*/
public $incrementing = true;
loadCount 方法
影响可能性:低
基础类 Illuminate\Database\Eloquent\Model
中添加了loadCount
方法。如果你的应用中也定义了 loadCount
方法,可能会和 Eloquent 中的相冲突。
影响可能性:非常低
Illuminate\Database\Eloquent\Concerns\HasAttributes
trait 中的 originalIsEquivalent
成员方法从 protected
改变为 public
。
影响可能性:低
当你的 Eloquent 模型使用了 Illuminate\Database\Eloquent\SoftDeletes
trait 时 deleted_at
成员属性 现将会自动转换 成为一个 Carbon
实例。你可以重写这个行为,通过为该成员属性编写你的自定义 accessor 或者手动将它添加到 casts
属性中:
protected $casts = ['deleted_at' => 'string'];
影响可能性:低
BelongsTo
关联关系中的 getForeignKey
和 getQualifiedForeignKey
方法已分别重命名为 getForeignKeyName
和 getQualifiedForeignKeyName
,使得方法名和在 Laravel 提供的其他关联关系中保持一致。
事件
fire 方法
影响可能性:低
Illuminate/Events/Dispatcher
类中的fire
方法 (在Larevel 5.4中不赞成使用) 已经被 移除 了。你应当使用它的替代方法 dispatch
。
异常处理器
ExceptionHandler 契约
影响可能性:低
Illuminate\Contracts\Debug\ExceptionHandler
契约中新增了 shouldReport
方法。 现在当你实现异常处理器的接口时,你需要同时实现此方法。
影响可能性:低
Illuminate\Foundation\Exceptions\Handler
类中 renderHttpException
方法的签名 有改动 。现在如果你在异常处理器中重写此方法,应当修改方法的签名以和其父类保持一致:
/**
* 将给定的 Http 异常转换为 Http 响应。
*
* @参数 \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface $e
* @返回 \Symfony\Component\HttpFoundation\Response
*/
protected function renderHttpException(HttpExceptionInterface $e);
Facades
Facade 服务解析
影响可能性:低
getFacadeAccessor
方法现在可以 只返回代表服务容器标识的字符串 ,之前该方法会返回一个对象实例。
邮件
Markdown 文件路径更改
影响可能性:高
如果你已经使用 vendor:publish
命令发布了 Laravel 的 Markdown 邮件组件,你需要将 /resources/views/vendor/mail/markdown
路径重命名为 text
。
并且 markdownComponentPaths
方法 已被重命名 为 textComponentPaths
。如果你要重写这个方法,你应该更新方法名,使之与其父类一致。
影响可能性:非常低
Illuminate\Mail\PendingMail
类中的 send
, sendNow
, queue
, later
和 fill
方法 已被更改 为需接收一个 Illuminate\Contracts\Mail\Mailable
实例作为参数,而不是 Illuminate\Mail\Mailable
实例。如果你要重写其中的方法,你需要更新其形参,和其父类保持一致。
队列
Pheanstalk 4.0
影响可能性:中
Laravel 5.8 提供了支持 ~4.0
发布版本的 Pheanstalk 队列。如果你正在应用中使用 Pheanstalk 库,请通过 Composer 升级你的库到 ~4.0
发布版本。
Job 契约
影响可能性:非常低
isReleased
, hasFailed
和 markAsFailed
方法 已被加入到 Illuminate\Contracts\Queue\Job
契约中 。如果你正在实现这个 interface ,你应该添加这些方法到你的实现代码中。
影响可能性:非常低
在 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 。
请求
影响可能性:低
现在,当请求输入是一个数组时, Illuminate\Foundation\Http\Middleware\TransformsRequest
中间件的 transform
方法将接收到「全限定」 请求输入的 key :
'employee' => [
'name' => 'Taylor Otwell',
],
/**
* 转换给定的值.
*
* @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
属性(在 Laravel 5.7 中已被弃用) 已更改为 $cachedScheme
。
Sessions
StartSession 中间件
影响可能性:非常低
Session 的持久性逻辑已 从 terminate()
方法移动到 handle()
方法。 如果你要重写其中的方法, 则应该更新它们以反映这些更改。
Support
优先使用字符串和数组类而不是辅助函数
影响可能性: 中等
所有的 array*
and 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
方法:
/**
* 获取已验证的属性和值。
*
* @return array
*/
public function validated();
如果你调用了这个接口,需要添加此方法的实现。
影响可能性: 非常低
Illuminate\Validation\Concerns\ValidatesAttributes
特性中的 parseTable
、 getQueryColumn
和 requireParameterCount
方法可见性从 protected
调整为了public
。
影响可能性: 非常低
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 比较工具 查看哪些更新对你而言更加重要。