php json转整型 php如何处理json中的数字类型【解析】

3次阅读

php json_decode默认将所有数字转为Float,需用(int)转换或json_bigint_as_string处理大整数,mysql写入前须显式指定pdo::param_int类型。

php json转整型 php如何处理json中的数字类型【解析】

json_decode 默认把数字当 float,不是 int

PHP 的 json_decode 在解析 JSON 字符串时,对所有数字(包括 1230-456)统一转成 float 类型,哪怕 JSON 里写的是纯整数。这不是 bug,是 PHP 早期为兼容 IEEE 754 浮点精度做的设计选择。

常见错误现象:json_decode('{"id": 123}')['id'] === 123.0 返回 false;用 is_int() 判断失败;数据库插入时被当成浮点写入 DECIMAL 或触发类型警告。

  • 如果 JSON 来源可控(比如自己生成),优先在 JSON 层就加引号变成字符串:{"id": "123"},再手动 (int) 转换
  • 若必须保留数字格式,且确定数值范围在 PHP int 安全范围内(通常 ≤ 253),可用 intval()强制类型转换(int)$data['id']
  • 注意:intval("123.9") → 123,但 intval("1e2") → 1 —— 不要对含科学计数法的 JSON 数字直接 intval

启用 JSON_BIGINT_AS_STRING 防止大整数变 0 或溢出

当 JSON 中出现超出 PHP int 表示范围的大整数(如 17 位以上订单号、mongodb ObjectId),json_decode 默认会把它转成 float,再转 int 就可能变 0 或错值(例如 9223372036854775807 变成 9223372036854776000)。

正确做法是开启 JSON_BIGINT_AS_STRING 标志,让大整数原样作为字符串返回:

立即学习PHP免费学习笔记(深入)”;

json_decode($json, false, 512, JSON_BIGINT_AS_STRING)

这样 {"order_id": 12345678901234567890} 中的 order_id 是字符串 "12345678901234567890",后续可安全传给 MySQL 的 BIGINT UNSIGNED 或调用 gmp_init() 处理。

  • 该标志只影响「超出平台 int 范围」的数字,小整数仍按默认规则走 float
  • PHP 7.4+ 支持,旧版本需自行正则预处理或改用 json_last_Error() + 重解析
  • 别漏掉第 3 个参数(depth),设太小(如 1)会导致嵌套 JSON 解析失败

自定义递归转换:把所有数字字段批量转 int(慎用)

有些老系统要求整个数组里所有数字都变 int,又不想逐个字段写 (int)。可以写一个递归函数做后处理,但必须明确边界条件——否则会把 pricerate 这类本该是 float 的字段也截断。

推荐只对明确标识为整型用途的 key 名做转换,比如 idstatuscount 等:

$intKeys = ['id', 'user_id', 'status', 'count', 'code'];<br>function castIntFields($data, $intKeys) {<br>    if (!is_Array($data)) return $data;<br>    foreach ($data as $k => $v) {<br>        if (is_numeric($v) && in_array($k, $intKeys)) {<br>            $data[$k] = (int)$v;<br>        } elseif (is_array($v)) {<br>            $data[$k] = castIntFields($v, $intKeys);<br>        }<br>    }<br>    return $data;<br>}
  • 不要无差别 is_numeric() + (int) 整个数组,会误伤 "123.00" 这种价格字符串
  • is_numeric("1e2") 返回 true,但 (int)"1e2" 是 1 —— 若 JSON 可能含科学计数法,先 filter_var($v, FILTER_VALIDATE_FLOAT) 判断
  • 性能上,深度嵌套时递归有开销,简单结构建议手动映射

MySQL 写入前检查:int 字段不能接受 float

即使 PHP 里用了 (int),如果数据库字段是 INT,而你传了 123.0(仍是 float 类型),PDO 或 mysqli严格模式下会报 SQLSTATE[HY000]: General error: 1366 Incorrect Integer value

真正保险的做法是在绑定参数时显式指定类型:

$stmt->bindValue(':id', $data['id'], PDO::PARAM_INT);
  • 别依赖自动类型推断,尤其用 execute($array) 批量绑定时,PDO::PARAM_STR 是默认行为
  • 如果用 laravel Eloquent,确保模型里声明了 $casts = ['id' => 'int'],它会在存库前自动转换
  • 注意:MySQL 8.0+ 对 STRICT_TRANS_TABLES 模式更敏感,本地开发和线上环境 SQL mode 不一致时容易漏掉这个坑

最麻烦的情况是 JSON 里混着 int/float 语义但没约定字段名,这时候光靠解析逻辑救不了,得推动上游改 schema 或加 type hint 字段。

text=ZqhQzanResources