json_decode И json_encode длинные целые без потери данных

Как отмечено в документации PHP, когда json_decodeВ структуре данных, содержащей длинные целые числа, они будут преобразованы в числа с плавающей точкой. Обходной путь должен использовать JSON_BIGINT_AS_STRING, который сохраняет их как строки вместо. когда json_encodeтакие значения, JSON_NUMERIC_CHECK закодируем эти числа обратно в большие целые числа:

$json  = '{"foo":283675428357628352}';
$obj   = json_decode($json, false, JSON_BIGINT_AS_STRING);
$json2 = json_encode($obj, JSON_NUMERIC_CHECK);
var_dump($json === $json2); // true

Использование этого метода для правильной обработки данных может привести к ошибкам. Если свойство содержит '123'числовая строка, которая должна оставаться строкой, она будет закодирована в целое число.

Я хочу получить объект с сервера, изменить одно свойство и затем вернуть всю структуру данных. Мне нужно сохранить оригинальные типы. Я не хочу поддерживать свойства, отличные от того, которым я манипулирую.

Есть ли реальный обходной путь для этого? У PHP больше нет проблем с большими типами, но json_decode рутина, кажется, устарела.

6

Решение

Пока ваша версия PHP может обрабатывать большие целые числа, то есть, если вы используете 64-битную версию PHP (на что-то кроме Windows), json_decode не имеет проблем с этим:

$json  = '{"foo":9223372036854775807}';
$obj   = json_decode($json);
$json2 = json_encode($obj);

var_dump(PHP_INT_MAX, $obj, $json2);

int(9223372036854775807)
object(stdClass)#1 (1) {
["foo"]=>
int(9223372036854775807)
}
string(27) "{"foo":9223372036854775807}"

Если целочисленные значения, которые вы должны обработать, превышают PHP PHP_INT_MAX-А ты просто не могу представлять их в PHP родных типов. Таким образом, у вас нет пути к загадке; вы не можете использовать нативные типы для отслеживания правильного типа и не можете заменить другие типы (например, строки вместо целых чисел), потому что это неоднозначно при кодировании обратно в JSON.

В этом случае вам придется изобрести собственный механизм отслеживания правильных типов для каждого свойства и обрабатывать такую ​​сериализацию с помощью пользовательского кодера / декодера. Например, вам нужно написать собственный декодер JSON, который может декодировать в пользовательский класс, например new JsonInteger('9223372036854775808')и ваш пользовательский кодировщик распознает этот тип и закодирует его в JSON 9223372036854775808 значение.

В PHP нет такой вещи.

4

Другие решения

Для чего это стоит, PHP Можно значения поддержки> PHP_INT_MAX с использованием пакета bcmath http://php.net/manual/en/book.bc.php но JSON немного более сложный вопрос.

Чтобы ответить на вопрос OP о том, почему они не могут кодировать значение из строки обратно в тип int в JSON, ответ заключается в шаге преобразования. При чтении исходной строки JSON, она является строкой и читается побайтово. При чтении значений они первоначально читаются как строка (как сам JSON, если строка), а затем приводятся к правильному типу в int или float в зависимости от наличия точки (.). Если значение больше чем PHP_INT_MAX тогда PHP преобразует его в двойное число, и вы теряете точность. Таким образом, используя JSON_BIGINT_AS_STRING скажет парсеру сохранить значение в виде строки и НЕ попытайтесь разыграть его, все должно быть хорошо, значение сохраняется в такте, пусть и в виде строки.

Проблема возникает, когда делать обратное, и делать json_encode($value, JSON_NUMERIC_CHECK) говорит PHP преобразовывать строковые числовые значения в int / float, но, похоже, это происходит ДО запись в строку JSON, вызывая значения> PHP_INT_MAX быть преобразованным в двойное представление, как 9.2233720368548e+19

Увидеть https://3v4l.org/lHL62 или ниже:

$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));

Результат:

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}"

К сожалению, не похоже, что есть способ решить эту проблему, глядя на константы JSON http://php.net/manual/en/json.constants.php Я не вижу ничего, что позволяло бы вам записывать целочисленные значения> PHP_INT_MAX в целые числа в JSON.

Извините, это не находит решения, но, надеюсь, устранит некоторую путаницу.

0

По вопросам рекламы [email protected]