PHP默认int无法正确处理大整数,必须全程用字符串配合BCMath(如bcadd('a','b',0))或GMP(如gmp_strval(gmp_add('a','b')))扩展;需严防PDO/json_decode默认转数字导致精度丢失。

PHP 默认的 int 类型根本不能“正确处理”大整数——它会在超出 PHP_INT_MAX(通常是 9223372036854775807)时静默转成 float,或直接回绕变负数,没有任何警告。所谓“正确处理”,本质是绕过原生整型,全程用字符串 + 专用扩展。
bcadd() 参数必须是字符串,且 scale 不能省略
bcadd() 看似简单,但传 int 或 float 就已经输了。PHP 会先尝试把数字转字符串,而 1e20 这类表示法一转就失真;更隐蔽的是,如果没传第三个参数 scale,它会读全局 bcscale() 设置——这个值可能被其他模块改过,导致结果末尾莫名补零或截断小数。
- 正确写法:
bcadd('12345678901234567890', '98765432109876543210', 0) - 错误写法:
bcadd(12345678901234567890, 98765432109876543210)(字面量在解析阶段就被截断) - 危险写法:
bcadd('123.45', '67.89')(依赖未设的全局精度,行为不可控) - 所有输入必须是纯数字字符串:不能有空格、逗号、
+符号前缀(除非是负数),否则静默失败
gmp_add() 返回 GMP 对象,不是字符串也不是 int
直接 echo gmp_add('123', '456') 看起来能输出,但那只是对象 toString 的默认行为;一旦参与字符串拼接、JSON 编码或条件判断,就会出问题。GMP 函数不接受 float 输入,也不接受含非法字符的字符串——gmp_add('123abc', '1') 会当作 0 处理,毫无提示。
- 必须显式转字符串:
gmp_strval(gmp_add('123', '456')) - 别用
(string)强转 GMP 对象,旧版本可能截断 - 检测扩展是否存在:
function_exists('gmp_add'),别假设一定启用 - Windows 下官方 PHP 包默认不带 GMP,
extension=php_gmp.dll会报“找不到指定模块”
从数据库和 JSON 进来的数字,第一步就错了
很多问题不是出在计算环节,而是数据刚进 PHP 就被污染了。PDO 默认把 BIGINT 字段映射为 int,json_decode() 默认把长数字转成 float——这两个动作都会导致精度不可逆丢失,后面再怎么用 bcadd 都救不回来。
立即学习“PHP免费学习笔记(深入)”;
- PDO 连接时加选项:
PDO::ATTR_STRINGIFY_FETCHES => true - JSON 解析时加标志:
json_decode($json, false, 512, JSON_BIGINT_AS_STRING) - Laravel 用户:在
config/database.php的 MySQL 连接配置里加'options' => [PDO::ATTR_STRINGIFY_FETCHES => true] - 别试图用
(string)$id补救——如果原始值已溢出回绕,转字符串只是把错的数字变成错的字符串
真正难的不是调哪个函数,而是让整个数据流从源头(数据库字段、API 响应体、表单提交)开始就保持字符串形态。只要中间任何一环用了 (int)、intval()、json_decode() 默认行为或 PDO 自动类型映射,精度就断了,而且很难定位是哪一步断的。



















