根本原因是php与java整数类型定义不同:php int平台相关,java int固定32位、long固定64位;php超范围整数自动转float致json序列化异常;应统一用string传输并显式类型检查。

PHP 和 Java 交互时整数精度不一致,根本原因不是“精度丢失”,而是双方对整数类型的默认解释不同:PHP 的 int 是平台相关(32/64 位有符号整数),而 Java 的 int 固定为 32 位有符号、long 固定为 64 位有符号。当 PHP 在 32 位环境或处理超大整数(如 > 2³¹−1)时,会自动转为 float,再序列化成 JSON 就变成科学计数法或小数,Java 解析时直接报错或截断。
用 JSON 传整数时 PHP 自动转 float 怎么禁?
PHP 7.1+ 提供了 JSON_PRESERVE_ZERO_FRACTION,但它只对 float 生效;真正关键的是避免整数被误判为 float —— 必须确保变量类型始终是 int 或 string。
- 传输前显式强转:
(int)$val或intval($val),但注意:若原始值已超出PHP_INT_MAX(如 9223372036854775807),强转会溢出回负数或 0 - 更安全做法:对可能超范围的整数(如数据库主键、时间戳微秒级),统一用
string类型传输,Java 端用BigInteger或Long.parseLong()解析 - PHP 侧序列化前检查:
is_int($val) && $val >= PHP_INT_MIN && $val ,否则走字符串分支
Java 接收 PHP JSON 里的大整数总变 0 或负数?
典型现象是 PHP 发送 "12345678901234567890"(字符串形式),但 Java 用 int 或 long 字段反序列化,Jackson 默认会尝试强制转换,超出范围就静默归零或溢出。
- 后端 DTO 字段别用基本类型:用
BigInteger(绝对安全)或String(保留原始表示,业务层再解析) - 如果必须用
long,加 Jackson 注解:@JsonFormat(shape = JsonFormat.Shape.STRING),强制按字符串解析再转 long,触发溢出异常而非静默错误 - Spring Boot 项目可在全局配置
spring.jackson.deserialization.use-big-decimal-for-floats=true,但这只影响浮点,对整数无效 —— 整数需单独处理
二进制协议(如 Protobuf / Thrift)里怎么定整数字段?
Protobuf 的 int32/int64 是语言中立的,但 PHP 的 protobuf 扩展(如 google/protobuf)在编码时仍依赖 PHP 变量类型:若 PHP 传入的是 float 或 string,可能被错误映射。
立即学习“PHP免费学习笔记(深入)”;
- 定义 schema 时,明确用
sint32/sint64(带符号变长编码,兼容负数)而非uint32(无符号,PHP 没原生支持) - PHP 端赋值前务必
is_int($val) ? $val : (int)round((float)$val),避免 float 输入;对超大值,改用Google\Protobuf\Int64Value包装 - Java 端接收
int64字段,对应 Java 的long,无需额外适配 —— 但要注意 Kotlin 中Long是可空类型,需判空
最易被忽略的一点:MySQL 的 BIGINT UNSIGNED(如 18446744073709551615)在 PHP 中无法用 int 表示(即使 64 位 PHP 也只支持有符号),必须全程以 string 流转,任何环节转 int 都会崩。这不是传输格式问题,而是底层类型鸿沟 —— 统一的前提是承认它不可桥接,只能绕行。










