PHP怎么保存小数5.6与7.4版本差异在哪_默认精度调整影响【技巧】

2次阅读

php 7.4+ json_encode() 对浮点数输出更精确,导致如 5.6 显示为 “5.6000000000000005”,而 PHP 5.6 输出 “5.6”;这源于底层格式化逻辑变更,并非 bug,需手动 round() 预处理以保证一致性。

PHP怎么保存小数5.6与7.4版本差异在哪_默认精度调整影响【技巧】

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),因为 precision ini 控制它,而默认值是 14(足够显示 5.6)
  • 真正容易被忽略的是:前端 JS 解析 PHP 输出的 JSON 时,如果用 === 比较字符串,会因 PHP 7.4 多出的尾数导致失败

text=ZqhQzanResources