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

2022-01-17 00:00:00 json numbers parsing php bigint

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

As noted in the PHP documentation, when json_decodeing a data structure containing long integers, they'll be converted to floats. The workaround is to use JSON_BIGINT_AS_STRING, which preserves them as strings instead. When json_encodeing such values, JSON_NUMERIC_CHECK will encode those numbers back into large integers:

$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',一个数字字符串,应该保持一个字符串,它将被编码为一个整数.

Using this method for a correct roundtrip of the data is prone to errors. If a property contains '123', a numeric string which should stay a string, it will be encoded to an integer.

我想从服务器获取一个对象,修改一个属性,然后把整个数据结构放回去.我需要保留原始类型.除了我正在操作的属性之外,我不想维护其他属性.

I want to get an object from the server, modify one property and than put the entire data structure back. I need to preserve the original types. I don't want to maintain properties other than the one I'm manipulating.

有什么真正的解决方法吗?PHP 对大整数不再有任何问题,但 json_decode 例程似乎已经过时了.

Is there any real workaround for this? PHP does not have any issues with big ints anymore, but the json_decode routine seems to be outdated.

推荐答案

只要你的 PHP 版本实际上可以处理大整数,这意味着如果你运行的是 64 位版本的 PHP (在一些 Windows以外),json_decode 没问题:

As long as your PHP version can actually handle large integers, meaning if you're running a 64-bit version of PHP (on something other than Windows), json_decode has no problem with it:

$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 的 PHP_INT_MAX,那么您只是 不能 以 PHP 原生类型表示它们.因此,您无法解决这个难题;您不能使用本机类型来跟踪正确的类型,也不能替换其他类型(例如字符串而不是整数),因为在编码回 JSON 时会产生歧义.

If the integer values you need to handle do exceed PHP's PHP_INT_MAX, you simply cannot represent them in PHP native types. So there's no way around the conundrum you have; you cannot use native types to track the correct type, and you cannot substitute other types (e.g. strings instead of integers), because that's ambiguous when encoding back to JSON.

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

In this case you will have to invent your own mechanism of tracking the correct types for each property and handle such serialisation with a custom encoder/decoder. For example, you'd need to write a custom JSON decoder which can decode to a custom class like new JsonInteger('9223372036854775808'), and your custom encoder would recognise this type and encode it to a JSON 9223372036854775808 value.

PHP 中没有内置这样的东西.

There's no such thing built into PHP.

相关文章