我想将json字符串解码为PHP对象,然后将该对象再次转换回json字符串,而不会丢失json中浮点数的精度。
如果你运行下面的示例,输出将是:
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_decode($json, true, 512, JSON_BIGINT_AS_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字符串中的数字但是我必须通过自己解析json而不使用json_decode函数。
我已经阅读了很多关于此事的帖子,但他们都只说了如何将json转换为对象(使用字符串),而不是如何将该对象再次转换为原始json作为json中的数字。
如果您想使用示例:http://sandbox.onlinephpfunctions.com/code/8d934874c93c4574d886dbbf645a6763ba1ba131
答案 0 :(得分:0)
是什么创建了你的json字符串?
虽然它在理论上是正确的,但它对于普通PHP程序员不需要的一定程度的疯狂也是准确的。这些值在32位(甚至64位)PHP内存中无法表示为浮点数或整数。顺便说一句,您发布的在线链接使用32位PHP。当PHP解码json时,它会在表示内存中的值时尽可能准确。您是否注意到溢出的integer2被解码为float,因此精度损失,但没有溢出?由于它永远无法在内存中表示这些疯狂准确的值,因此当您再次对对象进行编码时,会得到逻辑上相似但不同的json字符串。
您还应该问问自己,为什么需要json字符串与原始表示相同?如果你真的需要这种程度的准确性,我会考虑使用JAVA,你可以使用更高精度的数据类型(如BigInteger)。 PHP不是这种真正高精度的东西的最佳工具。 (无论如何,PHP 5)。
建议阅读: