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 - точности чисел с плавающей запятой, однако в конечном итоге все это связано с переходом от точности к использованию 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 answers
Это немного сводило меня с ума, пока я, наконец, не нашел эту ошибку, которая указывает вам на этот RFC, в котором говорится
В настоящее время
json_encode()
использует EG(точность), значение которого равно 14. Это означает, что для отображения (печати) номера используется не более 14 цифр. Двойной стандарт IEEE 754 поддерживает более высокую точность иserialize()
/var_export()
использует PG(serialize_precision), значение которого по умолчанию равно 17, чтобы быть более точным. Посколькуjson_encode()
использует EG(точность),json_encode()
удаляет нижние цифры дробь разделяет и уничтожает исходное значение, даже если значение с плавающей точкой PHP может содержать более точное значение с плавающей точкой.
И (курсив мой)
В этом RFC предлагается ввести новую настройку, например (точность)=-1 и PG(serialize_precision)=-1, которая использует режим zend_dtoa() 0, в котором используется лучший алгоритм округления чисел с плавающей запятой (-1 используется для обозначения режима 0).
Короче говоря, есть новый способ заставить PHP 7.1 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, это будет строка, так как она будет завернута в двойные кавычки.