PHP 7.4+ json_encode() 对浮点数输出更精确,导致如 5.6 显示为 “5.6000000000000005”,而 PHP 5.6 输出 “5.6”;这源于底层格式化逻辑变更,并非 bug,需手动 round() 预处理以保证一致性。
PHP 5.6 和 7.4 的 serialize() 对浮点数处理一致,但 json_encode() 行为有关键差异
PHP 默认不修改浮点数精度,但 json_encode() 在不同版本对小数的输出位数控制逻辑变了——这不是“保存”问题,而是“序列化为 JSON 字符串时是否截断尾部零”的表现差异。
例如:json_encode(5.6) 在 PHP 5.6 输出 "5.6",而 PHP 7.4 默认输出 "5.6000000000000005"(实际取决于 IEEE 754 表示和内部精度),但这不是 bug,是底层浮点数表示暴露程度提高。
- 根本原因:PHP 7.3+ 启用了更严格的浮点数 JSON 序列化策略,默认使用
JSON_PRESERVE_ZERO_FRACTION风格的隐式行为(虽未显式启用该 flag) - 影响场景:API 返回、日志记录、前端解析失败(如
parseFloat("5.6000000000000005") !== 5.6仍为 true,但字符串比对或调试时易误导) - 不涉及
serialize()、数据库写入、变量赋值等操作——这些环节浮点数值本身没变
用 ini_set('precision', '14') 或 json_encode($v, JSON_PARTIAL_OUTPUT_ON_ERROR) 无法解决 JSON 尾数问题
很多人试过调整 precision ini 配置,发现对 json_encode() 输出无效。这是因为 JSON 编码器绕过了 precision 设置,直接调用底层 C 的 snprintf("%.*G") 格式化逻辑,且 PHP 7.4+ 改用了更精确的舍入算法。
-
ini_set('precision', '2')只影响var_dump()、echo $float等字符串转换,不影响json_encode() -
JSON_PARTIAL_OUTPUT_ON_ERROR是容错 flag,不控制精度 - 真正起作用的是
JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE这类 flag,和精度无关
可靠方案:手动格式化浮点字段再 JSON 编码
如果你需要稳定输出如 "5.6" 而非 "5.6000000000000005",必须在进 json_encode() 前做显式格式化。