php的json_encode/json_decode数字精度问题源于json规范不保留格式、float类型无末尾零、浮点转字符串默认科学计数法及float精度上限2⁵³;解决方案包括:用sprintf或number_format预转字符串、json_bigint_as_string处理大整数、字段级单独格式化。

PHP 的 json_encode 和 json_decode 在处理数字精度时存在几个关键限制,不是“出错”,而是由底层机制和 JSON 规范共同决定的。要准确控制精度,得清楚每一步在哪丢失、为什么丢失,以及怎么绕过。
浮点数在 json_encode 中丢失小数位(如 12.3400 → 12.34)
这不是 bug,是设计使然:JSON 标准不区分 12.34 和 12.3400,它只认数值语义,不存格式信息;而 PHP 的 float 类型本身也不记录末尾零——12.3400 被解析成 float 后就已是 12.34。
真正能起作用的方案只有:提前转成字符串
- 用
sprintf('%.4f', $price)→ 得到"12.3400"(四舍五入) - 用
number_format($lat, 6, '.', '')→ 得到"35.123000"(补零,适合坐标) - 别用
(string)$float,它走默认精度(受precisionini 配置影响),不可控
极小/极大浮点数变成科学计数法(如 0.000001659 → 1.659e-6)
这是 PHP 把 float 转字符串时的默认行为,目的是避免超长输出。JSON 里它仍是合法数字,但可读性差,前端也可能解析异常。
Miller (mlr) 是一个命令行工具,用于查询、整形和重新格式化名称索引数据,如 CSV、TSV、JSON 和 JSON Lines。它将 awk、sed、cut、join 和 sort 的功能整合到一个专为结构化数据处理而构建的单一工具中。
解决方法同样是格式化为固定小数形式的字符串
-
sprintf('%.8f', $x)强制输出 8 位小数,0.000001659变成"0.00000166" - 若需截断而非四舍五入,先做
floor($x * 1e8) / 1e8,再格式化 - 注意:结果是字符串,前端要用
parseFloat()或+才能当数字用
大整数(如 ID、时间戳)在 json_decode 后变不准
PHP 的 float 最多精确表示 2⁵³(约 16 位十进制数)。超过这个范围的整数(比如 18 位订单号),用 json_decode($json) 默认会转成 float,精度直接丢失。
可靠做法是让大数以字符串身份进入 JSON
- 编码时加
JSON_BIGINT_AS_STRING:json_encode($data, JSON_BIGINT_AS_STRING) - 前提是原始数据里大数已经是字符串类型,例如
['id' => '1234567890123456789'] - 或手动预处理:遍历数组,把长度 ≥ 15 的数字字段用
strval()转成字符串
字段级独立精度控制(如 latitude 保留 6 位、price 保留 2 位)
serialize_precision 是全局配置,没法按字段设。硬要差异化,就得在组装响应数组时,对每个字段单独格式化:
$res['lat'] = number_format($lat, 6, '.', '');$res['lng'] = number_format($lng, 6, '.', '');$res['amount'] = sprintf('%.2f', $amount);- 最终
json_encode($res)输出的全是字符串字段,精度可控、格式明确
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










