PHP版本从7.3升级到8.1中遇到的坑汇总贴[不定期更新]

这是来自2019年的前情提要:将PHP版本从5.6升级到7.3中遇到的坑汇总贴[不定时更新]

提示:这是一篇技术博客,请普通玩家不必关注此文。

总之,随着时代的变化,为了优化网站执行效率,为了实装更多新科技,为了与各种新型框架接轨,在3年前将PHP版本升到7.3之后,今次将再次将其升级到8.1。

目前经过大约一周的密集调试,升级工程已经基本完成(不过只是确认了各种基础功能能正常工作,可能会有各种小功能会导致异常)

因此这是另一份技术留底。希望有同类问题的人能搜到此篇Blog

PHP8不支持从Null,或者未定义变量中执行各种数组/类的操作

最常见的情况是,假设一个数组 $arr = DB::select() blabla这样的操作,但是这个数组并没有从数据库中查询出任何值,接下来如果使用 foreach 或者类似操作,可能会报 invalid argument supplied for foreach() 错误。

(对,是可能,因为有时候不一定会出这个错误,因为历史遗留太多,暂未查明)

另外,对于需要链式调用的对象(例如 blabla()->foo()->bar() 这种)的情况,如果中间有一个返回了null,那么整个链式调用会断掉。需要手动处理。
PS:PHP8中有一个nullsafe写法可以很方便的解决↑上面这个问题,具体可参见PHP官方文档 https://www.php.net/manual/zh/language.oop5.basic.php#language.oop5.basic.nullsafe

解决方案:挨个改吧……写个if !empty 什么的……

除以0现在是Error而不是Warning

如题,现在除以0会直接error报错 division by zero

解决方案:挨个改……

一大票隐式类型转换全部失效

例如:数组的下标只能是数字或者字符串,不能是另一个数组或者对象或者null(以前版本会进行隐式转换)。出现这种错误的话会报错 Illegal offset type

解决方案:挨个改……这个改起来会很痛苦,只能看到一个报错改一个。

常量名无法自动转为对应字符串

旧版本的PHP中,如果一个字符串忘了打引号就使用(这相当于一个常量),那么会自动的将其转为等同于这个常量名的字符串。

举例  foo(aaa);
如果不存在一个名叫aaa的常量,那么等同于 foo(“aaa”);
新版本中这个转换失效,会报错未定义的常量 (Undefined constant)

解决方案:挨个加引号!

create_function 函数被废弃

在旧版本还没有回调函数的之后,create_function可以用于在类似于array_map之类的函数中执行类似于回调函数的功能

新版本中会直接报错 create_function 未定义

解决方案:改为回调函数的模式

implode不再支持分隔符在后,操作变量在前的写法。

参见 https://www.php.net/manual/zh/function.implode.php

虽然我自己没用这种写法,但许多第三方库用了这个,如果这个第三方库不更新,需要手动更新,如果这是个用composer管理的库……那就先无能狂怒一会吧!

解决方案:手动改~

许多函数如果要求一个数组作为参数,如果传入参数不是一个数组,那么会直接报错。

会报类似于 Uncaught TypeError: foo(): Argument #1 ($bar) must be of type array, string given 之类的错误(也有可能是 null given)

没有什么规律,似乎是非常混乱的出现。

解决方案:找到一个改一个。

单例类的方法必须显式指明 public static function

某些第三方库可能会偷懒只写 function 在PHP8中必须要显式标明

解决方案:改改改~

 

之后有新的还会不定期更新。

新版 Edge (Chromium 内核) 在特定情况下,页面上如果有大量不可见元素时,可能导致神秘卡顿现象的问题成因以及解决办法

前言

从标题看起来,这并不是一个与 Linodas 有关的博文,对吧?

但是,标题说的这个现象,这的确是由修复 Linodas 的一个故障引起的,加之我并没有技术 Blog 一样的东西,想来想去,还是发在 Linodas 的 Blog 上最合适。

这个问题是什么呢?简单来说:

这应该是,小学生套高数公式,然后发现变量为特定数字时,某一型号的计算器型号算出来的结果和其他不一样。

——by 某不愿透露姓名的……

此现象的简要阐述

那么,简单来说就是,在之前的几周,有用户回报在用 Edge 访问 Linodas 的许多页面的时候,都会遇到非常莫名的卡顿现象。

本来以为只是 JS 方面的问题(毕竟我自己不太会前端,JS写得烂也是正常),但经过仔细排查,逐步排查了 JS 问题和页面布局问题之后,发现这个问题并不简单。

具体如何发现故障点就过程就不阐述了(其实很简单,二分法嘛,故障不在这一半,就一定在另一半)。最终发现问题竟然非常简单:

Edge (Chromium 内核版本) 会在页面上读取了一个大型样式表 (CSS文件) 之后。
如果页面上大量元素被设为了不可见
(这包括 类似于 <div hidden> 或 style=’display:none’ 等)时

部分特定的 Edge (经证实与版本号无关) 将会产生巨量卡顿 & 失去响应。
卡顿时间将会随着元素的数量而迅速上升(经过测试大约300个DOM开始出现可体感的卡顿),同时导致CPU占用率飙升,风扇狂响等。

测试页面

以下是一个测试页面,请使用 Edge 访问:https://www.linodas.com/temp/edge_stuck_bug.html

此网页的核心是包含了一个被包裹在

<div hidden></div>

中的巨量(600个)

<div>Edge</div>

对,就是如此简单的结构。(可以自行查看源代码)

当然,除此之外,这个页面还引用了一个 Tailwind CSS 库 的完整版。(必须要引用这个库才能重现此 Bug,但实际上无论用不用到其中的样式,都会触发这个 Bug,这一页面就没有使用其样式)

页面上的JS元素是为了方便视觉察觉而设置的,与此 Bug 无关,可以自行去除。

请注意:此故障在纯本地环境(地址栏是file:///C:/blabla.html  这样的时候)将不会重现,但如果是 本地 Web 环境(如http://localhost/blabla.html)这样的情况,会重现。

请注意,部分 Edge 并不会触发这个 Bug,经过大约30名用户左右的实测,有大约一半用户的 Edge 是完全不会触发这个现象。此故障与版本号无关,截止本文发表日,我的 Edge 版本 102.0.1245.44 会触发此 Bug

目前此故障从未在 Chrome / Firefox / 其他基于 Chromium 的浏览器 / 移动版 Edge 下出现过。

如果你没有遇到卡顿现象,那么可以不看了,如果你遇到了,那么可以继续向下看。

解决办法

很显然,在一个不可见元素里面包含很多元素,这是网页设计中很正常的部分,无论是遮罩,模态窗口,标签页,模拟<select>等,许多网页设计都需要在一个不可见元素中包含很多元素。

因此这个故障几乎是无法避免的。无法解决。

当然,可以有变相解决办法,例如:

1.避免使用不可见元素

简单来说就是用 visibility: hidden; 的方式取代
但是,大家都知道,这个 CSS 会导致元素的占位被表现出来,不是真正的不可见。

2.使用扭曲(脏,Hack)的方式来替换

最简单的办法是使用
position: absolute;visibility: hidden;left:-99999px;

可以完全平替掉
display:none

缺点嘛……这也太丑啦!而且如果有很多东西都涉及这个就会很麻烦。

3.修改页面结构,不使用不可见元素,直接去除,需要用的时候用 Ajax/其他办法 临时加载进来

要改后端代码,愿意改也没问题啦。

4.不用Edge

完美方案!

但是!

经过我询问一个不愿透露姓名的 Microsoft 员工之后,得到了一个惊人的答案。

在 Edge 的启动快捷方式后面附上参数
--disable-features=msEEPageClassifier
之后,就会恢复正常。

实测有效!

想不通?对把,想不通就对了,因为我也想不通。

此参数的意思至今不明,截至 UTC+8 2022-06-21 22:38 为止,所有搜索引擎均无此参数的解释。个人猜测是 Edge 的某个内部私有参数。

设置此启动参数后重启 Edge (可以通过 edge://version 确认参数是否有效) 之后就能消除此故障,经过测试,所有用户加此参数后都无法再复现此故障。

根据群众猜测,从参数名来看,或许是页面内容(统计学意义上的)分类量化(存储以备后用),但这也无法确定。毕竟没有任何搜索引擎有结果告诉我们答案。

那么这篇博文的意义是什么?

  • 督促微软赶紧修复这个 Bug!
  • 如果有高人能完整解剖这个故障的成因,那就再好不过,了却我一桩疑惑。
  • 方便有人遇到同类故障的时候,可以搜索到本博文。
  • 如果你有兴趣,也可以前往 Linodas 随意的玩一玩。

将PHP版本从5.6升级到7.3中遇到的坑汇总贴[不定时更新]

提示:这是一篇技术博客,请普通玩家不必关注此文。

因为种种主观和客观原因,虽然我写的其他程序都是基于PHP7的了,但 Linodas 因为历史遗留太多,一直没有升级到最新的PHP版本,一直保持在5.6版本。

不过由于最近的一些神秘计划,因此在最近就正好将PHP更新到了CentOS 6.8支持的最高的7.3版。搬迁之后马上就遇到了一大堆问题。

因此,下面就是一份维修记录,除了作为技术留底,也方便了今后有人在网上搜索同类问题的时候能看到此文。

安装完php7之后记得装其他组件。

比如GD库,Redis等等。否则会报错找不到class

PHP7不再支持传统的 mysql_ 开头的库,需要用mysqli_ 开头的替换

注意不能直接复制粘贴替换,否则会死的很惨。
可以先用 http://www.seabreezecomputers.com/mysql2mysqli/ 这个工具转换旧的代码,注意也不要直接转换完了就替换,也会死得很惨。
请务必要针对自己的mysql库的实际情况(OO化的还是过程化的),具体调整代码才可以工作。

=& new classname 不能用

直接删掉&即可

一般个人不会用这种写法,我是改一个第三方库里面的

PHP7不支持 preg_replace 中使用 /e 修饰符,需要用 preg_replace_callback 替换

这里一定要小心的修复,我在这里遇到的问题是模板引擎太老,导致所有模板生成全是空白,查阅error_log没有报错,所以花了许多时间解决这个问题。

现在一般大家写的时候都不会用/e修饰符了,所以问题不大。

NaN和False的关系

用一张图可以说明此问题

对于有多个PHP版本情况,记得要修改crontab中的CLI方式执行的PHP文件

例如在cron中如果有类似
/usr/bin/php /www/domain/123.php
这样的内容,需要修改为类似
/usr/bin/php73 /www/domain/123.php
这样。

类似 $aaa->$bbb[‘ccc’]的格式的解析顺序变化

这个一般很多迁移指南里面都写为第一条,我当时感觉“啊好像我游没有用到这个写法啊”就没管。

结果还是中招了,不过只有一个很小的地方遇到了,问题不大,改了就好。

可以用下列正则快速的找出问题代码
\$[A-Za-z0-9]+\-\>\$[A-Za-z0-9]+\[
修改办法也很简单,改为
$aaa->{$bbb['ccc']}
就可以了

之后还会有更多更新,敬请期待。