como - PHP7.1 json_encode() Problema de flotación
convertir string a int php (6)
Como desarrollador de complementos, no tengo acceso general a la configuración de php.ini de un servidor. Entonces, basado en la respuesta de Machavity, escribí este pequeño código que puedes usar en tu script PHP. Simplemente colóquelo encima del script y json_encode seguirá funcionando como de costumbre.
if (version_compare(phpversion(), ''7.1'', ''>='')) {
ini_set( ''serialize_precision'', -1 );
}
En algunos casos es necesario establecer una variable más. Estoy agregando esto como una segunda solución porque no estoy seguro de si la segunda solución funciona bien en todos los casos en que la primera solución ha demostrado funcionar.
if (version_compare(phpversion(), ''7.1'', ''>='')) {
ini_set( ''precision'', 17 );
ini_set( ''serialize_precision'', -1 );
}
Esta no es una pregunta, ya que es más un cuidado.
json_encode()
una aplicación que usa
json_encode()
a PHP7.1.1 y vi un problema con los flotadores que se cambian para extender a veces 17 dígitos.
Según la documentación, PHP 7.1.x comenzó a usar
serialize_precision
lugar de precisión al codificar valores dobles.
Supongo que esto causó un valor de ejemplo de
472,185
convertirse
472.18500000000006
después de que ese valor pasó por
json_encode()
.
Desde mi descubrimiento, he vuelto a PHP 7.0.16 y ya no tengo el problema con
json_encode()
.
También intenté actualizar a PHP 7.1.2 antes de volver a PHP 7.0.16.
El razonamiento detrás de esta pregunta proviene de
PHP - Precisión de número flotante
, sin embargo, la razón final de todo esto se debe al cambio de precisión al uso de serialize_precision en
json_encode()
.
Si alguien sabe de una solución a este problema, estaría más que feliz de escuchar el razonamiento / solución.
Extracto de una matriz multidimensional (antes):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
y después de pasar por
json_encode()
...
"staticYaxisInfo":
{
"17":
{
"variable_id": "17",
"static": "1",
"min": 0,
"max": 472.18500000000006,
"locked_static": "1"
}
},
Estaba codificando valores monetarios y tenía cosas como la codificación
330.4600000000000363797880709171295166015625
a
330.4600000000000363797880709171295166015625
.
Si no desea o no puede cambiar la configuración de PHP y conoce de antemano la estructura de los datos, hay una solución muy simple que me funcionó.
Simplemente tírelo a una cadena (los dos siguientes hacen lo mismo):
$data[''discount''] = (string) $data[''discount''];
$data[''discount''] = '''' . $data[''discount''];
Para mi caso de uso, esta fue una solución rápida y efectiva. Solo tenga en cuenta que esto significa que cuando lo decodifique de JSON, será una cadena ya que estará entre comillas dobles.
Esto me volvió loco por un momento hasta que finalmente encontré este error que te señala a este RFC que dice
Actualmente,
json_encode()
usa EG (precisión) que se establece en 14. Eso significa que se usan 14 dígitos como máximo para mostrar (imprimir) el número. IEEE 754 double admite una mayor precisión yserialize()
/var_export()
usa PG (serialize_precision) que se establece en 17 por defecto para ser más preciso. Comojson_encode()
usa EG (precisión),json_encode()
elimina los dígitos más bajos de las partes de fracción y destruye el valor original incluso si el flotante de PHP podría contener un valor flotante más preciso.
Y (énfasis mío)
Este RFC propone introducir una nueva configuración EG (precisión) = - 1 y PG (serialize_precision) = - 1 que usa el modo 0 de zend_dtoa () que usa un mejor algoritmo para redondear los números flotantes (-1 se usa para indicar el modo 0) .
En resumen, hay una nueva forma de hacer que PHP 7.1
json_encode
use el nuevo y mejorado motor de precisión.
En
php.ini
necesita cambiar
serialize_precision
a
serialize_precision = -1
Puedes verificar que funciona con esta línea de comando
php -r ''$price = ["price" => round("45.99", 2)]; echo json_encode($price);''
Deberías conseguir
{"price":45.99}
Las otras soluciones no funcionaron para mí. Esto es lo que tuve que agregar al comienzo de la ejecución de mi código:
if (version_compare(phpversion(), ''7.1'', ''>='')) {
ini_set( ''precision'', 17 );
ini_set( ''serialize_precision'', -1 );
}
Puede cambiar [max] => 472.185 de un flotante a una cadena ([max] => ''472.185'') antes de json_encode (). Como json es una cadena de todos modos, la conversión de sus valores flotantes a cadenas antes de json_encode () mantendrá el valor que desee.
Tuve el mismo problema pero solo serialize_precision = -1 no resolvió el problema. Tuve que hacer un paso más, para actualizar el valor de precisión de 14 a 17 (como estaba configurado en mi archivo ini PHP7.0). Aparentemente, cambiar el valor de ese número cambia el valor del flotador calculado.