使用PHP在json中进行编码和解码时不会丢失精度
我想将一个json字符串解码为PHP对象,然后将该对象再次解码为json字符串,而不会丢失json中浮点数的精度 如果运行下面的示例,输出将是:使用PHP在json中进行编码和解码时不会丢失精度,php,json,floating-point,Php,Json,Floating Point,我想将一个json字符串解码为PHP对象,然后将该对象再次解码为json字符串,而不会丢失json中浮点数的精度 如果运行下面的示例,输出将是: JSON: string '{ "integer1": 10000, "integer2": 100000999499498485845848584584584, "float1": 1.121212, "float2": 8.226347662837406e+09 }' (length=130) JSON WITHOUT SPACES [1]
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)
我希望字符串[1]和[2]相等,或者至少不降低精度。
我知道十进制数字不能在PHP浮点中精确表示,我知道您可以使用选项json\u decode($json,true,512,json\u BIGINT\u AS\u STRING)
在PHP中将数字表示为字符串。但是使用该选项,我可以从该对象重新生成原始json
<?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());
是什么创建了json字符串 虽然它在理论上是正确的,但它也精确到了普通PHP程序员不需要的疯狂程度。这些值在32位(甚至64位)PHP内存中不能表示为浮点数或整数。顺便说一下,您发布的在线链接使用32位PHP。当PHP解码json时,它在表示内存中的值时会尽可能精确。您是否注意到溢出的整数2被解码为浮点数,因此有精度损失,但没有溢出?因为它永远无法在内存中表示这些异常精确的值,所以当您再次编码对象时,会得到一个逻辑上相似但不同的json字符串 您还应该问自己,为什么需要json字符串与原始表示形式相同?如果你真的需要这种精确度,我会考虑使用java,在那里你可以使用更高精度的数据类型(比如BigInteger)。PHP并不是处理此类高精度内容的最佳工具。(无论如何是PHP 5) 建议如下: