json_decode() 默认将所有数字解析为 float,导致大整数精度丢失;应使用 JSON_BIGINT_AS_STRING 选项转为字符串再安全转换。

PHP 中用 json_decode() 解析 JSON 后,原本的整数被转成 float,再强转 (int) 可能失真——这不是 bug,是 PHP 7.1+ 对大整数的默认行为,关键在解码时就控制类型。
为什么 json_decode() 后数值变 float?
JSON 标准不区分 int/float,PHP 默认把所有数字都解析为 float(即使看起来是 123)。当 JSON 里有超大整数(比如 16 位以上),float 无法精确表示,后续 (int) 强转会截断或错位。
- 典型现象:
json_decode('{"id":9223372036854775807}')['id']在 64 位系统上可能变成9.2233720368548E+18,强转(int)得到9223372036854775808(溢出) - 根本原因:PHP 默认不启用大整数保护,
json_decode()不做类型推断
正确做法:用 JSON_BIGINT_AS_STRING 选项
让 json_decode() 把超大数字原样保留为字符串,后续按需转换——这是最安全、兼容性最好的方案。
- 必须传第二个参数
true(返回关联数组),否则选项无效 - 第三个参数是深度,第四个才是选项位掩码
- 示例:
json_decode($json, true, 512, JSON_BIGINT_AS_STRING) - 之后用
filter_var($str, FILTER_VALIDATE_INT)或ctype_digit()+intval()判断并转整型,避免 float 中间态
哪些场景不能用 JSON_BIGINT_AS_STRING?
如果你对接的接口明确要求所有字段都是 int 类型(比如某些 SDK 的 strict mode),且确认数据永远不超过 PHP_INT_MAX(通常 9223372036854775807),可以关闭该选项,但必须加校验:
立即学习“PHP免费学习笔记(深入)”;
- 用
is_int()检查解码后是否已是整型(小数字可能碰巧是 int) - 否则用
floor($val) == $val && $val = PHP_INT_MIN判断是否可安全转 int - 避免直接
(int)$val,因为 float 转 int 在溢出时行为不可控(如(int)9.2233720368548E+18结果依赖平台)
真正麻烦的不是“怎么转”,而是“什么时候该转”。JSON 里的数字语义决定处理方式:ID、时间戳、金额要保精度,计数、状态码可宽松。别默认全转 int,先看业务含义。











