I want to decode a json string to PHP object and then the object back again to json string without losing precision for floats numbers in json.
If you run the sample below the output would be:
JSON:
string '{
"integer1": 10000,
"integer2": 100000999499498485845848584584584,
"float1": 1.121212,
"float2": 8.226347662837406e+09
}' (length=130)
JSON WITHOUT SPACES [1]:
string '{"integer1":10000,"integer2":100000999499498485845848584584584,"float1":1.121212,"float2":8.226347662837406e+09}' (length=112)
OBJECT:
object(MyObject)[1]
public 'integer1' => int 10000
public 'integer2' => float 1.000009994995E+32
public 'float1' => float 1.121212
public 'float2' => float 8226347662.8374
JSON FROM OBJECT [2]:
string '{"integer1":10000,"integer2":1.000009994995e+32,"float1":1.121212,"float2":8226347662.8374}' (length=91)
I want string [1] and [2] to be equal or at least not to loose precision.
I know that decimal numbers can´t be represented exactly in PHP floats and I know that you can use the option json_decode($json, true, 512, JSON_BIGINT_AS_STRING) to represent number as string in PHP. But using that option I can re-generate the original json from the object.
<?php
$json = <<<EOT
{
"integer1": 10000,
"integer2": 100000999499498485845848584584584,
"float1": 1.121212,
"float2": 8.226347662837406e+09
}
EOT;
// json_last_error_msg (PHP 5 >= 5.5.0)
if (!function_exists('json_last_error_msg')) {
function json_last_error_msg() {
static $errors = array(
JSON_ERROR_NONE => null,
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
);
$error = json_last_error();
return array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})";
}
}
class MyObject
{
/** @var int|float */
public $integer1;
/** @var int|float */
public $integer2;
/** @var int|float */
public $float1;
/** @var int|float */
public $float2;
public function __construct($json)
{
$this->fromJson($json);
}
public function fromJson($json)
{
$result = json_decode($json);
if (json_last_error() != JSON_ERROR_NONE) {
die('json_decode error: '.json_last_error_msg());
};
$this->integer1 = $result->integer1;
$this->integer2 = $result->integer2;
$this->float1 = $result->float1;
$this->float2 = $result->float2;
}
public function toJson()
{
$json = json_encode($this);
if (json_last_error() != JSON_ERROR_NONE) {
die('json_decode error: '.json_last_error_msg());
};
return $json;
}
}
echo 'JSON: ';
var_dump($json);
echo 'JSON WITHOUT SPACES [1]: ';
var_dump(preg_replace('/\s+/', '', $json));
$object = new MyObject($json);
echo 'OBJECT: ';
var_dump($object);
echo 'JSON FROM OBJECT [2]: ';
var_dump($object->toJson());
I suppose I could add extra metadata to the object and indicate if the string property it was a number in the original json string but then I would have to parse the json by my self and not using the json_decode function.
I have read a lot of posts on this matter but all of them said only how to convert json to object (using string) but not how to convert again that object to the original json as a number in json.
If you want to play with the sample: http://sandbox.onlinephpfunctions.com/code/8d934874c93c4574d886dbbf645a6763ba1ba131