新项目用的 PHP 7.1.13
版本,在使用过程中发现 浮点类型
数据经过 json_encode
之后会出现精度问题。
举个例子:
1 2 3 4 5 6 7 8 9 $data = [ 'stock' => '100', 'amount' => 10, 'price' => 0.1 ]; var_dump($data); echo json_encode($data);
输出结果:
1 2 3 4 5 6 7 8 9 10 11 array(3) { ["stock"]=> string(3) "100" ["amount"]=> int(10) ["price"]=> float(0.1) } { "stock":"100", "amount":10, "price":0.10000000000000001 }
网上说可以通过调整 php.ini
中 serialize_precision (序列化精度)
的大小来解决这个问题。
1 2 3 4 5 6 7 ; When floats & doubles are serialized store serialize_precision significant ; digits after the floating point. The default value ensures that when floats ; are decoded with unserialize, the data will remain the same. ; The value is also used for json_encode when encoding double values. ; If -1 is used, then dtoa mode 0 is used which automatically select the best ; precision. serialize_precision = 17
按照说明,将这个值改为 小于 17
的数字就解决了这个问题。
后来又发现一个折中的办法,就是将 float
转为 string
类型。
1 2 3 4 5 6 7 8 9 $data = [ 'stock' => '100', 'amount' => 10, 'price' => (string)0.1 ]; var_dump($data); echo json_encode($data);
输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 array(3) { ["stock"]=> string(3) "100" ["amount"]=> int(10) ["price"]=> string(3) "0.1" } { "stock":"100", "amount":10, "price":"0.1" }
这样子也解决了问题,但是总感觉不太方便,所以就有了这个函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /** * @param $data 需要处理的数据 * @param int $precision 保留几位小数 * @return array|string */ function fix_number_precision($data, $precision = 2) { if(is_array($data)){ foreach ($data as $key => $value) { $data[$key] = fix_number_precision($value, $precision); } return $data; } if(is_numeric($data)){ $precision = is_float($data) ? $precision : 0; return number_format($data, $precision, '.', ''); } return $data; }
测试:
1 2 3 4 5 6 7 8 9 10 11 12 $data = [ 'stock' => '100', 'amount' => 10, 'price' => 0.1, 'child' => [ 'stock' => '99999', 'amount' => 300, 'price' => 11.2, ], ]; echo json_encode(fix_number_precision($data, 3));
输出结果:
1 2 3 4 5 6 7 8 9 10 { "stock":"100", "amount":"10", "price":"0.100", "child":{ "stock":"99999", "amount":"300", "price":"11.200" } }
PS: php 版本 >= 7.1 均会出现此问题。