PHP 7.1 默认 serialize_precision=17 导致浮点数序列化精度下降,引发反序列化失真、缓存失效、校验失败等问题;应显式设为-1或改用json_encode/DECIMAL等更安全方案。

PHP 5.6 升级到 PHP 7.1 时,序列化精度(serialize_precision)配置项的行为发生关键变更:它从默认值 -1(表示“使用最高可用精度”)改为默认 17,且该值直接影响 serialize()、unserialize() 和 var_export() 对浮点数的处理。升级后若未调整,可能导致浮点数反序列化结果不一致、缓存失效、接口数据校验失败等隐蔽问题。
为什么 serialize_precision 变更会影响业务
PHP 用科学记数法存储浮点数,但序列化时需转为字符串表示。精度设置过低(如默认 17),会导致小数位被截断或四舍五入,尤其对金融计算、地理坐标、科学数据等敏感场景影响显著:
-
serialize(0.1 + 0.2)在 PHP 5.6(serialize_precision=-1)中可能生成"d:0.30000000000000004;";在 PHP 7.1+(默认 17)中可能变成"d:0.3;" - 若旧缓存中存有高精度序列化字符串,新版本反序列化后数值已失真,可能引发金额误差或条件判断错误
- 前后端通过序列化字符串交换数据时,精度不一致会导致签名验证失败或 JSON 转换异常
如何检查和恢复兼容行为
不建议直接依赖默认值,而应显式配置并统一全环境:
- 在
php.ini中添加或修改:serialize_precision = -1(恢复 PHP 5.6 行为) - 若无法改全局配置,可在代码启动时动态设置:
ini_set('serialize_precision', '-1');(需放在所有序列化操作前,如入口文件顶部) - 验证是否生效:
var_dump(ini_get('serialize_precision'));应输出 string(2) "-1"
更安全的替代方案:避免依赖 serialize 处理浮点数
长期来看,serialize 并非传输浮点数的理想方式。推荐以下实践:
立即学习“PHP免费学习笔记(深入)”;
- 用
json_encode($data, JSON_PRESERVE_ZERO_FRACTION)替代,JSON 标准明确支持小数精度保留 - 数据库存储浮点字段时,优先用
DECIMAL类型;PHP 层读取后以字符串传递,避免 float 类型中间转换 - 涉及金额、坐标等关键数据,序列化前先格式化为固定小数位字符串:
sprintf('%.10f', $value),再参与序列化
上线前必须做的验证动作
仅改配置不够,需实测关键路径:
- 找出项目中所有调用
serialize()/unserialize()的地方,特别是缓存、Session、队列消息体 - 对含浮点数的典型数据结构做对比测试:分别在 PHP 5.6 和 7.1 环境下执行
serialize($sample),比对输出字符串是否一致 - 检查 Redis/Memcached 中存量缓存是否因精度变化导致
unserialize()后数值异常(可写脚本批量抽检)



















