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

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

  $ json ='{“  foo“:283675428357628352}'; 
$ obj = json_decode($ json,false,JSON_BIGINT_AS_STRING);
$ json2 = json_encode($ obj,JSON_NUMERIC_CHECK);
var_dump($ json === $ json2); // true
</ code> </ pre>

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

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

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

展开原文

原文

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

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.

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.

dongxian8272
dongxian8272 如何在json中将大整数作为字符串发送?
5 年多之前 回复
duanbei8904
duanbei8904 啊,对不起,我现在看到为什么不......
5 年多之前 回复
doujianwan7570
doujianwan7570 你至少可以使用JSON_BIGINT_AS_STRING和JSON_NUMERIC_CHECK...3v4l.org/7NkrR来获得一个好的往返-这对你的用例来说还不够好吗?
5 年多之前 回复
dquv73115
dquv73115 是的,你是对的。我认为json_decode不应该将bigint转换为字符串或浮点数。当发送修改后的对象时,服务器对无效数据类型说“不”。
5 年多之前 回复
duan5731
duan5731 是的,但建议是使用第三方库。我喜欢保持我的应用程序很小。
5 年多之前 回复
doubo1711
doubo1711 你问的问题有点令人困惑。总结一下:你想要json_decode一个数据集,改变一些属性,然后再次json_encode;你的问题是,当这样做时,大整数会变成浮点数或字符串。我说得对吗?
5 年多之前 回复
duanlei4759
duanlei4759 你检查了类似的线程stackoverflow.com/questions/15659325/...
5 年多之前 回复

2个回答

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}"

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.

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.

There's no such thing built into PHP.

duannao3819
duannao3819 怎么样甚至更大的整数,如“38位精度”
3 年多之前 回复
dongshi8038
dongshi8038 嗯,我认为没有解决方案。 但我希望你能赢得声誉。 谢谢。 我的生产系统使用linux,它在那里很好。
5 年多之前 回复
dougao9864
dougao9864 好吧,请注意:“64位平台的最大值通常约为9E18,Windows除外,它总是32位。”
5 年多之前 回复
douningchang3610
douningchang3610 我使用的是Windows 8.1(64位),apache v2.4(64位)和php v5.6.9(64位)。
5 年多之前 回复

For what it's worth, PHP can support values > PHP_INT_MAX using the bcmath package http://php.net/manual/en/book.bc.php but JSON is a slightly more difficult issue.

To answer the OP's question of why they can't encode the value from a string back to an int type in the JSON, the answer lies in the conversion step. When reading the original JSON string in, it's a string, and read byte by byte. When reading values, they're initially read as a string (as the JSON itself if a string), and later cast to the correct type to an int or a float depending upon the presence of a period (.). If the value is greater than PHP_INT_MAX then PHP converts it to a double, and you lose precision. Thus using JSON_BIGINT_AS_STRING will tell the parser to keep the value as a string and NOT try to cast it, everything should be good, the value is kept in tact, albeit a string.

The problem comes when doing the inverse, and doing json_encode($value, JSON_NUMERIC_CHECK) tells PHP to cast string numeric values into either int/float, but this appears to happen BEFORE writing to the JSON string, causing values > PHP_INT_MAX to be converted into a double representation like 9.2233720368548e+19

See https://3v4l.org/lHL62 or below:

$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));

Result:

string(29) "{"max": 92233720368547758071}"
object(stdClass)#1 (1) {
  ["max"]=>
  float(9.2233720368548E+19)
}
object(stdClass)#1 (1) {
  ["max"]=>
  string(20) "92233720368547758071"
}
string(30) "{"max":"92233720368547758071"}"
string(29) "{"max":9.223372036854776e+19}"

Unfortunately, it doesn't appear that there is a way to solve this, looking at the JSON constants http://php.net/manual/en/json.constants.php I don't see anything that allows you to write integer values > PHP_INT_MAX into ints within the JSON.

Sorry this doesn't find a solution but hopefully clears up some confusion.

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐