PHP7.1 закодировать в JSON() вопрос поплавка
Это не вопрос, так как это скорее осознание. Я обновил приложение, которое использует json_encode() для PHP7. 1. 1, и я видел проблему с поплавками, которые иногда расширяются до 17 цифр. Согласно документации, PHP 7.1.x начал использовать serialize_precision вместо точности при кодировании двойных значений. Я предполагаю, что это вызвало примерное значение
472.185
Стать
472.18500000000006
После этого пошел через json_encode(). С момента моего открытия я вернулся к PHP 7.0.16, и у меня больше нет проблемы с json_encode(). Я также попытался обновить до PHP 7.1.2, прежде чем вернуться обратно к PHP 7.0.16.
Рассуждения, стоящие за этим вопросом, действительно вытекают изPHP - Floating Number Precision , однако конечная причина этого заключается в изменении от точности к использованию serialize_precision в json_encode().
Если кто-нибудь знает решение этой проблемы, я буду более чем счастлив слушайте рассуждения / исправления.
Отрывок из многомерного массива (до):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
И после прохождения через json_encode()...
"staticYaxisInfo":
{
"17":
{
"variable_id": "17",
"static": "1",
"min": 0,
"max": 472.18500000000006,
"locked_static": "1"
}
},
5 ответов:
Это немного сводило меня с ума, пока я наконец не нашел этот баг, который указывает вам на Этот RFC , который говорит
Сейчас
json_encode()используется например, (точность), который 14. Это означает, что для отображения (печати) номера используется не более 14 цифр. IEEE 754 double поддерживает более высокую точность иserialize()/var_export()использует PG (serialize_precision), который установлен в 17 по умолчанию, чтобы быть более точным. Посколькуjson_encode()использует EG (точность),json_encode()удаляет нижние цифры дроби разделяет и уничтожает исходное значение, даже если float PHP может содержать более точное значение float.И (курсив мой)
Короче говоря, есть новый способ заставить PHP 7.1В этом документе предлагается ввести новый параметр например, (точность)=-1 и ПГ(serialize_precision)=-1, что использует zend_dtoa()'ы режим 0, который использует лучше algorigthm для округления числа с плавающей точкой (-1 используется, чтобы указать 0 режим).
json_encodeиспользовать новый и улучшенный механизм точности. В php.ini вам нужно изменитьserialize_precisionнаserialize_precision = -1Вы можете проверить, что он работает с этой командной строкой
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'Вы должны получить
{"price":45.99}
Как разработчик плагинов я не имею общего доступа к php.ini-настройки сервера. Итак, основываясь на ответе Machavity, я написал этот небольшой фрагмент кода, который вы можете использовать в своем PHP-скрипте. Просто поместите его поверх скрипта, и json_encode продолжит работать как обычно.
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'serialize_precision', -1 ); }
У меня была та же проблема, но только serialize_precision = -1 не решил проблему. Мне пришлось сделать еще один шаг, чтобы обновить значение точности с 14 до 17 (как это было установлено в моем файле PHP7.0 ini). По-видимому, изменение значения этого числа изменяет значение вычисляемого поплавка.
Другие решения не сработали для меня. Вот что мне пришлось добавить в начале выполнения кода:
if (version_compare(phpversion(), '7.1', '>=')) { ini_set( 'precision', 17 ); ini_set( 'serialize_precision', -1 ); }
Я кодировал денежные ценности и имел такие вещи, как
330.46кодирование в330.4600000000000363797880709171295166015625. Если вы не хотите или не можете изменить настройки PHP, и вы заранее знаете структуру данных, есть очень простое решение, которое сработало для меня. Просто приведите его к строке (оба следующие делают то же самое):$data['discount'] = (string) $data['discount']; $data['discount'] = '' . $data['discount'];Для моего случая использования это было быстрое и эффективное решение. Просто обратите внимание, что это означает, что когда вы декодируете его обратно из JSON, это будет строка, так как она будет обернута в double двойные кавычки.
Comments