Nicholas Atkinson
Nicholas Atkinson

Reputation: 47

json_decode turning long numbers into scientific notation

I have this RAW JSON being returned and when I apply json_decode to access the data as an array it turns the trackingNumber into scientific notations. Is there any possible way to avoid this without compromising/rounding the integer or can I loop through the RAW JSON without decoding it? I've tried changing the precision and formatting it with number_format and both did work to an extent. However, there were some changes in the numbers around the middle of the integer as if it was rounded.

Original JSON data:

{
  "data": {
    "shipments": [
      {
        "packages": [
          {
            "responseDetails": {
              "trackingNumber": 420217949361269903504794752430
            }
          }
        ]
      }
    ]
  }
}

When json_decode gets involved:

{
  "data": {
    "shipments": [
      {
        "packages": [
          {
            "responseDetails": {
              "trackingNumber": 4.202179493612699e+29,
            }
          }
        ]
      }
    ]
  }
}

Changing precision:

<?php
  ini_set('precision', 30);
  $trackingNumber = 4.202179493612699e+29;
  print $trackingNumber;

  // Displays: 420217949361269887002807894016
?>

Using number_format():

<?php
  $trackingNumber = number_format(4.202179493612699e+29, 0, '.', '');
  print $trackingNumber;

  // Displays: 420217949361269887002807894016
?>

Upvotes: 2

Views: 1982

Answers (2)

jacouh
jacouh

Reputation: 8741

I would propose another solution if you use an older PHP then 5.4.0 within that JSON_BIGINT_AS_STRING is not defined. The idea is to handle trackingNumber as string, instead of bigInt. Any way, a tracking number can be an alphanumeric string in real life. If you cannot revise it manually, we shall convert it programatically. Following is a solution:

<?php

$strJSON = <<<EOF
{  "data": {
    "shipments": [
      {
        "packages": [
          {
            "responseDetails": {
              "trackingNumber": 420217949361269903504794752430
            }
          }
        ]
      }
    ]
  }
}
EOF;
//
// convert trackingnumber into string by double quoting the integer:
//
$strJSON = preg_replace('/"trackingNumber":\s*(\d+)/', '"trackingNumber": "$1"', $strJSON);
//
// here $strJSON is like this:
//     ...
//     "trackingNumber": "420217949361269903504794752430"
//     ...
//
//echo "<pre>" . $strJSON . "</pre>";
//exit;
//
$objJSON = json_decode($strJSON);
//
echo "<pre>";
var_dump($objJSON);
echo "</pre>";
?>

The above code gives:

object(stdClass)#5 (1) {
  ["data"]=>
  object(stdClass)#4 (1) {
    ["shipments"]=>
    array(1) {
      [0]=>
      object(stdClass)#3 (1) {
        ["packages"]=>
        array(1) {
          [0]=>
          object(stdClass)#2 (1) {
            ["responseDetails"]=>
            object(stdClass)#1 (1) {
              ["trackingNumber"]=>
              string(30) "420217949361269903504794752430"
            }
          }
        }
      }
    }
  }
}

Upvotes: 1

Michal Hynčica
Michal Hynčica

Reputation: 6169

This is because by default the big numbers are converted to float which is hurting their precision.

The json_decode() fourth param allows you to set options for decoding. You can use option JSON_BIGINT_AS_STRING to force conversion to string instead of float. I guess that you don't need to do any calculations with the number so working with string should be fine.

The whole function call might look like this:

$result = json_decode($jsonString, false, 512, JSON_BIGINT_AS_STRING);

Upvotes: 3

Related Questions