json_decode AND json_encode long integers without losing data

前端 未结 2 716
野的像风
野的像风 2020-12-04 01:38

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

2条回答
  •  一生所求
    2020-12-04 02:24

    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.

提交回复
热议问题