Как отмечено в документации 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
рутина, кажется, устарела.
Пока ваша версия 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 нет такой вещи.
Для чего это стоит, 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.
Извините, это не находит решения, но, надеюсь, устранит некоторую путаницу.