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() 前做显式格式化。
立即学习“PHP免费学习笔记(深入)”;
推荐做法(兼容 5.6–8.x):
// 对单个值
$rounded = round($value, 10);
$json = json_encode(['price' => $rounded]);
// 或批量处理数组(注意只处理数字键/指定键)
function normalizeFloats($data, $precision = 10) {
if (is_float($data)) {
return round($data, $precision);
}
if (is_array($data)) {
return array_map(function($v) use ($precision) {
return normalizeFloats($v, $precision);
}, $data);
}
return $data;
}
- 用
round($x, 10)而非sprintf("%.1f", $x):避免字符串化后丢失数值类型(尤其后续还要计算) - 精度设为 10 是经验值:既能消除 7.4+ 的冗余尾数,又不会在 0.1 + 0.2 场景下误判为 0.30000000000000004 → 0.3
- 不要全局替换所有 float:有些业务依赖完整精度(如金融风控中间值)
数据库写入和 var_dump 不受此影响,但要注意 MySQL 的 DECIMAL vs FLOAT
PHP 层面的 json_encode() 差异不会污染数据库存储。但如果你把 5.6 直接插进 MySQL 的 FLOAT 字段,MySQL 自己会按 IEEE 754 存储,读出来可能仍是 5.6000000000000005——这和 PHP 版本无关,是存储引擎决定的。
- 存小数务必用
DECIMAL(10,2)而非FLOAT,否则 PHP 5.6 和 7.4 都会遇到同样问题 -
var_dump(5.6)在两个版本都显示float(5.6),因为precisionini 控制它,而默认值是 14(足够显示 5.6) - 真正容易被忽略的是:前端 JS 解析 PHP 输出的 JSON 时,如果用
===比较字符串,会因 PHP 7.4 多出的尾数导致失败











