php 7.1 报错 a non well formed numeric value encountered

最近在接触支付的时候,遇到这样的问题,并不是支付本身的,而是生成支付的订单号出现的。
源代码如下

1
2
3
4
5
//  生成转款单号 便于测试
function createPayid()
{
return date('Ymdhis', time()).substr(floor(microtime()*1000),0,1).rand(0,9);
}

但是在高性能的PHP7下会出现这样的问题a non well formed numeric value encountered;

PHP只给出到行,而谷歌得到的结果也没有太多的参考价值,虽然报错一样,但代码方式并不一样。

那怎么办?

剥茧抽丝1

date('Ymdhis', time()) 抽离,变成这样。

1
2
3
4
5
function createPayid()
{
$number= date('Ymdhis', time());
return $number . substr(floor(microtime()*1000),0,1).rand(0,9);
}

仍然报错a non well formed numeric value encountered,仍然报return $number . substr(floor(microtime()*1000),0,1).rand(0,9);出错。

那么问题不出在date('Ymdhis', time())

剥茧抽丝2

将 后面的rand(0,9)剥离变成

1
2
3
4
5
6
function createPayid()
{
$number= date('Ymdhis', time());
$number . = substr(floor(microtime()*1000),0,1);
return $number . rand(0,9);
}

问题仍然执行 报错行数为$number . = substr(floor(microtime()*1000),0,1),报错信息没变:a non well formed numeric value encountered

剥茧抽丝3

经理了前面两步,我确认了问题出现在substr(floor(microtime()*1000),0,1);那么只要一层层的排除包裹的函数即可得到出错的真正代码;
最后,我确认问题出在microtime()*1000;

原因分析

原因就在于这个很少用的方法microtime(),通过查看手册可以得知他的值是一个字符串

1
2
3
4
5
6
mixed microtime ([ bool $get_as_float ] )
microtime — 返回当前 Unix 时间戳和微秒数
microtime() 当前 Unix 时间戳以及微秒数。本函数仅在支持 gettimeofday() 系统调用的操作系统下可用。
如果调用时不带可选参数,本函数以 "msec sec" 的格式返回一个字符串,其中 sec 是自 Unix 纪元(0:00:00 January 1, 1970 GMT)起到现在的秒数,msec 是微秒部分。字符串的两部分都是以秒为单位返回的。

如果给出了 get_as_float 参数并且其值等价于 TRUE,microtime() 将返回一个浮点数。

因为msecsec中间有space空格

解决办法

microtime()增加一个参数true,变成如下

1
2
3
4
5
//  生成转款单号 便于测试
function createPayid()
{
return date('Ymdhis', time()).substr(floor(microtime(true)*1000),0,1).rand(0,9);
}

到此可以说这个错误与PHP71没有任何关系是使用的bug,错误的用了microtime()