PHP序列化大浮点数出现舍入与格式问题,如何保留原格式?
解决PHP序列化浮点数时自动转为科学计数法的问题
首先,你遇到的是PHP原生serialize()函数的默认行为:当浮点数的数值过大(或过小)时,它会自动用科学计数法来存储这个值,这是由底层浮点数的表示机制决定的。要在不大幅改动现有代码的前提下解决这个问题,有两个非常实用的方案:
方案1:用JSON序列化替代(改动最小,推荐优先尝试)
如果你的数组里只有普通数据类型(数组、字符串、数值、布尔、null),完全可以用json_encode()和json_decode()来替代原生的序列化方法。JSON默认不会将这类浮点数转为科学计数法,还能保证数值的原始格式:
// 替换原来的serialize // $newData = serialize(array('ep' => 50733372961735.4)); // 改成: $newData = json_encode(array('ep' => 50733372961735.4), JSON_PRESERVE_ZERO_FRACTION); // 输出结果: echo "New data: " . $newData; // 会得到:New data: {"ep":50733372961735.4} // 反序列化的时候改成json_decode $unserialized = json_decode($newData, true); var_dump($unserialized['ep']); // 输出 float(50733372961735.4)
JSON_PRESERVE_ZERO_FRACTION参数是为了确保即使浮点数末尾是.0也不会被转成整数,完美保留原始格式。这个方案几乎不需要改动现有代码,只是替换两个函数名,不管数组层级多深都能自动处理。
方案2:自定义序列化函数(支持PHP特殊类型)
如果你的数组里包含PHP特有的类型(比如对象、资源),JSON就不太适用了,这时候可以写一个自定义的序列化函数,递归遍历数组把浮点数转成非科学计数法的字符串,序列化后再存,反序列化时再转回来:
// 自定义序列化:处理所有层级的浮点数 function customSerialize($data) { array_walk_recursive($data, function(&$value) { if (is_float($value)) { // 把浮点数转成无科学计数法的字符串,去掉末尾多余的0和小数点 $value = rtrim(rtrim(sprintf('%.15f', $value), '0'), '.'); } }); return serialize($data); } // 自定义反序列化:把字符串转回浮点数 function customUnserialize($serialized) { $data = unserialize($serialized); array_walk_recursive($data, function(&$value) { if (is_string($value) && is_numeric($value)) { $value = (float)$value; } }); return $data; } // 使用示例 $originalData = array('ep' => 50733372961735.4); $serialized = customSerialize($originalData); echo "New data: " . $serialized; // 输出:New data: a:1:{s:2:"ep";s:15:"50733372961735.4";} // 反序列化验证 $unserialized = customUnserialize($serialized); var_dump($unserialized['ep']); // float(50733372961735.4)
这个方案只需要把你代码里的serialize()换成customSerialize(),unserialize()换成customUnserialize()就可以了,不管数组嵌套多复杂,array_walk_recursive都会自动遍历到所有元素,不需要手动修改每一层的结构。
内容的提问来源于stack exchange,提问作者Anand
相关产品推荐
相关产品推荐

