JSON_decode JSON_encode 小数位丢失

php7.2 Laravel 5.8

$a = '{"orderAmt":500.00}';
$a_json_decode = json_decode($a,true);
$a_json_encode = json_encode($a_json_decode);
dd($a_json_decode,$a_json_encode);

dd结果

//$a_json_decode
array:1 [
  "orderAmt" => 500.0
]

//$a_json_encode
"{"orderAmt":500}"

服务器返回数据是json格式的,需要排序后再转换成字符串,去除双引号后,再验签,但json_decode后小数位就丢失了

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案

先扔结论与建议

结论: 从 PHP 5.6.6+ 开始,json_encode 支持使用 JSON_PRESERVE_ZERO_FRACTION 选项以告知引擎确保浮点数始终编码为浮点数,但对于形如 500.00 (值为 500,精确到小数点后两位的浮点数)仅能保证最终输出 500.0
建议:与上游协商,使用字符串类型的 500.00,或使用字符串拼接 JSON (不建议,会降低可读性)

代码片段(上下文继承 Laravel 的 Command 类,但其实直接写 php 文件用 cli 运行亦可)

$data = [
    'float' => 500.00,
];

dump($data);

$this->info(json_encode($data, JSON_PRESERVE_ZERO_FRACTION));

输出

array:1 [
  "float" => 500.0
]
{"float":500.0}

而且,经实践,即使临时配置 serialize_precision 为 10,在初始化数组时使用 number_format 函数格式化小数位数,最后在 json_encode 时填入选项 JSON_PRESERVE_ZERO_FRACTION | JSON_NUMERIC_CHECK 也仅能输出 500.0

参考资料:
[中文]PHP: json_encode - Manual
[英文]PHP: php.ini 核心配置选项说明 - Manual
[英文]PHP: 预定义常量 - Manual(用于 JSON 编码)

4年前 评论
讨论数量: 7

先扔结论与建议

结论: 从 PHP 5.6.6+ 开始,json_encode 支持使用 JSON_PRESERVE_ZERO_FRACTION 选项以告知引擎确保浮点数始终编码为浮点数,但对于形如 500.00 (值为 500,精确到小数点后两位的浮点数)仅能保证最终输出 500.0
建议:与上游协商,使用字符串类型的 500.00,或使用字符串拼接 JSON (不建议,会降低可读性)

代码片段(上下文继承 Laravel 的 Command 类,但其实直接写 php 文件用 cli 运行亦可)

$data = [
    'float' => 500.00,
];

dump($data);

$this->info(json_encode($data, JSON_PRESERVE_ZERO_FRACTION));

输出

array:1 [
  "float" => 500.0
]
{"float":500.0}

而且,经实践,即使临时配置 serialize_precision 为 10,在初始化数组时使用 number_format 函数格式化小数位数,最后在 json_encode 时填入选项 JSON_PRESERVE_ZERO_FRACTION | JSON_NUMERIC_CHECK 也仅能输出 500.0

参考资料:
[中文]PHP: json_encode - Manual
[英文]PHP: php.ini 核心配置选项说明 - Manual
[英文]PHP: 预定义常量 - Manual(用于 JSON 编码)

4年前 评论
wanghan

这不是小数点丢失,是类型的问题,如果500.00是字符串就不会丢失

4年前 评论

应该不是丢失,是省略了,我试了下500.01就没问题。

4年前 评论

json格式不会特别区分integer和float,所以对于500.00和500到底是500还是500.00取决于引擎,像java的gson就是会转成500.00

4年前 评论

先扔结论与建议

结论: 从 PHP 5.6.6+ 开始,json_encode 支持使用 JSON_PRESERVE_ZERO_FRACTION 选项以告知引擎确保浮点数始终编码为浮点数,但对于形如 500.00 (值为 500,精确到小数点后两位的浮点数)仅能保证最终输出 500.0
建议:与上游协商,使用字符串类型的 500.00,或使用字符串拼接 JSON (不建议,会降低可读性)

代码片段(上下文继承 Laravel 的 Command 类,但其实直接写 php 文件用 cli 运行亦可)

$data = [
    'float' => 500.00,
];

dump($data);

$this->info(json_encode($data, JSON_PRESERVE_ZERO_FRACTION));

输出

array:1 [
  "float" => 500.0
]
{"float":500.0}

而且,经实践,即使临时配置 serialize_precision 为 10,在初始化数组时使用 number_format 函数格式化小数位数,最后在 json_encode 时填入选项 JSON_PRESERVE_ZERO_FRACTION | JSON_NUMERIC_CHECK 也仅能输出 500.0

参考资料:
[中文]PHP: json_encode - Manual
[英文]PHP: php.ini 核心配置选项说明 - Manual
[英文]PHP: 预定义常量 - Manual(用于 JSON 编码)

4年前 评论

php这种弱类型的 .00这种就直接string吧 对谁都好

4年前 评论

精度的问题吧。

4年前 评论
aab

建议不要使用浮点数, 就算要用, 最好也要使用浮点数字符串.

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!