json_decode和json_encode长整数而不丢失数据

时间:2015-06-02 07:29:51

标签: php json parsing numbers bigint

如PHP文档中所述,当json_decode包含长整数的数据结构时,它们将被转换为浮点数。解决方法是使用JSON_BIGINT_AS_STRING,它将它们保留为字符串。当json_encode这些值时,JSON_NUMERIC_CHECK会将这些数字编码回大整数:

$json  = '{"foo":283675428357628352}';
$obj   = json_decode($json, false, JSON_BIGINT_AS_STRING);
$json2 = json_encode($obj, JSON_NUMERIC_CHECK);
var_dump($json === $json2); // true

使用此方法进行正确的数据往返很容易出错。如果属性包含'123',一个应该保留字符串的数字字符串,它将被编码为整数。

我想从服务器获取一个对象,修改一个属性,然后再将整个数据结构放回去。我需要保留原始类型。我不想维护我正在操纵的属性。

这有什么真正的解决方法吗? PHP不再存在大的问题,但json_decode例程似乎已经过时了。

2 个答案:

答案 0 :(得分:4)

只要您的PHP版本实际上可以处理大整数,这意味着如果您正在运行64位版本的PHP (在某些other than Windows上),{{1没有问题:

json_decode

如果您需要处理的整数值超过PHP的$json = '{"foo":9223372036854775807}'; $obj = json_decode($json); $json2 = json_encode($obj); var_dump(PHP_INT_MAX, $obj, $json2); int(9223372036854775807) object(stdClass)#1 (1) { ["foo"]=> int(9223372036854775807) } string(27) "{"foo":9223372036854775807}" ,那么您只需不能在PHP本机类型中表示它们。因此,你无法解决这个难题;您不能使用本机类型来跟踪正确的类型,也不能替换其他类型(例如字符串而不是整数),因为在编码回JSON时这是不明确的。

在这种情况下,您必须创建自己的跟踪每个属性的正确类型的机制,并使用自定义编码器/解码器处理此类序列化。例如,您需要编写一个自定义JSON解码器,它可以解码为PHP_INT_MAX等自定义类,您的自定义编码器会识别此类型并将其编码为JSON new JsonInteger('9223372036854775808')值。

PHP中没有这样的东西。

答案 1 :(得分:0)

对于它的价值,PHP 可以使用bcmath软件包http://php.net/manual/en/book.bc.php支持值> PHP_INT_MAX,但JSON则稍微困难一些。

要回答OP为何不能将值从字符串编码回JSON中的int类型的问题,答案在于转换步骤。读入原始JSON字符串时,它是一个字符串,并逐字节读取。读取值时,它们最初会被读取为字符串(如果是字符串,则为JSON本身),然后根据句点(。)的存在将其转换为正确的类型为int或float。如果该值大于name tag Art0 sport Art1 (null) Art2 sport Art2 health ,则PHP会将其转换为双精度值,您将失去精度。因此,使用PHP_INT_MAX会告诉解析器将值保留为字符串,并且尝试对其进行强制转换,一切都应该很好,即使字符串,该值也应保持不变。

在进行逆运算时会出现问题,并且执行JSON_BIGINT_AS_STRING告诉PHP将字符串数字值转换为int / float,但这似乎是在之前写入JSON字符串时发生的,导致值> json_encode($value, JSON_NUMERIC_CHECK)转换为类似PHP_INT_MAX的双精度表示形式

请参见https://3v4l.org/lHL62或以下版本:

9.2233720368548e+19

结果:

$bigger_than_max = '{"max": ' . PHP_INT_MAX . '1}'; // appending 1 makes > PHP_INT_MAX
var_dump($bigger_than_max);
var_dump(json_decode($bigger_than_max));
var_dump(json_decode($bigger_than_max, false, 512, JSON_BIGINT_AS_STRING));

var_dump(json_encode(json_decode($bigger_than_max, false, 512, JSON_BIGINT_AS_STRING)));
var_dump(json_encode(json_decode($bigger_than_max, false, 512, JSON_BIGINT_AS_STRING), JSON_NUMERIC_CHECK));

不幸的是,似乎没有一种方法可以解决这个问题,请查看JSON常量http://php.net/manual/en/json.constants.php。我看不到任何允许您将整数值> PHP_INT_MAX写入JSON中的int的方法。

对不起,这找不到解决方案,但希望能消除一些混乱。