PHP7 serialize_precision 配置不当导致 json_encode() 浮点小数溢出错误

@yangweijie 2019-11-22 03:10:56发表于 yangweijie/note blogphp

情是这样的,项目里发现一个奇怪的现象,json_encode一个带浮点价格的数据, 出现溢出, 比如:

$depth) return $d; if(is_array($d)){ foreach ($d as $i => $v) { $d[$i] = json_encode_pre($v, $depth, $level+1); } return $d; } if(is_float($d)){ # 测试发现number_format有效数字低于18(保守取16)时,不会溢出 $p = 16 - strlen(intval($d)); $f = number_format($d, $p); if($p>1){ $f = preg_replace('/0+$/','', $d); } return $d; } return $d; } echo number_format(277.2, 14); // 当18位有效数字处理(277.2已有4位有效数字) // 277.199999999999989 echo number_format(277.2, 12); // 当16位 // 277.2000000000000 echo json_encode(json_encode_pre(277.2)); // "277.2" 看到这结果时, 便猜测是有效数字位数的问题导致了溢出, PHP怎么会有这么蠢的设计呢?这是我当时的想法. 然后想着是不是能从源码下手, 于是查了下php源码, 发现这段代码: static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */ { size_t len; char num[PHP_DOUBLE_MAX_LENGTH]; php_gcvt(d, (int)PG(serialize_precision), '.', 'e', num); len = strlen(num); if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_DOUBLE_MAX_LENGTH - 2) { num[len++] = '.'; num[len++] = '0'; num[len] = '\0'; } smart_str_appendl(buf, num, len); } 是的, 竟然发现了配置项serialize_precision, 这个配置我当初的理解是serialize()方法用的, 而我当初尝试修改过配置项precision, 然并卵, 原来json_encode会用到serialize_precision, 于是修改php.ini, 把它设为16, 原来是17还是18忘了.