PHP7.1 JSON encodage () Float Issue
ce n'est pas une question car il est plus d'un être conscient. J'ai mis à jour une application qui utilise json_encode()
à PHP7.1.1 et je voyais un problème avec les flotteurs changés pour parfois étendre 17 chiffres. Selon la documentation, PHP 7.1.x a commencé à utiliser serialize_precision
au lieu de la précision lors de l'encodage de valeurs doubles. Je suppose que cela a causé une valeur d'exemple de
472.185
pour devenir
472.18500000000006
après cette valeur est passé par json_encode()
. Depuis ma découverte, je suis revenu à PHP 7.0.16 et je n'ai plus le problème avec json_encode()
. J'ai aussi essayé de mettre à jour vers PHP 7.1.2 avant de revenir à PHP 7.0.16.
le raisonnement derrière cette question ne provient de PHP-Floating Number Precision , mais la fin toute la raison pour cela est en raison du passage de la précision à l'utilisation de serialize_precision dans json_encode()
.
si quelqu'un connaît une solution à ce problème, je serais plus qu'heureux d'écouter le raisonnement/correction.
Extrait de tableau multidimensionnel (avant):
[staticYaxisInfo] => Array
(
[17] => stdClass Object
(
[variable_id] => 17
[static] => 1
[min] => 0
[max] => 472.185
[locked_static] => 1
)
)
et après avoir traversé json_encode()
...
"staticYaxisInfo":
{
"17":
{
"variable_id": "17",
"static": "1",
"min": 0,
"max": 472.18500000000006,
"locked_static": "1"
}
},
5 réponses
cela m'a rendu un peu dingue jusqu'à ce que j'ai finalement trouvé ce bug qui vous indique ce RFC qui dit
Actuellement
json_encode()
utilise par exemple(de précision) qui est fixé à 14. Cela signifie que 14 chiffres au plus sont utilisés pour afficher (imprimer) le numéro. IEEE 754 double supporte une plus grande précision etserialize()
/var_export()
utilise PG (serialize_precision) qui définit à 17 be par défaut être plus précis. Depuisjson_encode()
utilise EG (précision),json_encode()
enlève les chiffres inférieurs des parties de fraction et détruit la valeur originale même si le flotteur de PHP pourrait tenir la valeur flottante plus précise.
Et (l'emphase est mienne)
ce RFC propose d'introduire un nouveau réglage EG (precision) = -1 et PG (serialize_precision) = -1 qui utilise le mode 0 de zend_dtoa () qui utilise un meilleur algorithme pour arrondir les nombres flottants (-1 est utilisé pour indiquer 0 mode) .
en bref, il y a une nouvelle façon de faire PHP 7.1 json_encode
utiliser le nouveau moteur de précision améliorée. Dans php.ini vous devez remplacer serialize_precision
par
serialize_precision = -1
vous pouvez vérifier qu'il fonctionne avec cette ligne de commande
php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'
Vous devriez obtenir
{"price":45.99}
en tant que développeur de plugin, je n'ai pas d'accès général au php.paramètres d'initialisation d'un serveur. Donc, basé sur la réponse de Machavity j'ai écrit ce petit morceau de code que vous pouvez utiliser dans votre script PHP. Mettez-le simplement en haut du script et json_encode continuera de fonctionner comme d'habitude.
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'serialize_precision', -1 );
}
j'ai eu le même problème mais seulement serialize_precision = -1 n'a pas résolu le problème. J'ai dû faire un pas de plus, pour mettre à jour la valeur de précision de 14 à 17 (comme il a été mis sur mon PHP7.0 fichier ini). Apparemment, changer la valeur de ce nombre change la valeur du flotteur calculé.
les autres solutions n'ont pas fonctionné pour moi. Voici ce que j'ai dû ajouter au début de l'exécution de mon code:
if (version_compare(phpversion(), '7.1', '>=')) {
ini_set( 'precision', 17 );
ini_set( 'serialize_precision', -1 );
}
j'encodais des valeurs monétaires et j'avais des choses comme 330.46
encodant en 330.4600000000000363797880709171295166015625
. Si vous ne souhaitez pas, ou ne pouvez pas, modifier les paramètres de PHP et que vous connaissez la structure des données à l'avance, il y a une solution très simple qui a fonctionné pour moi. Il suffit de le lancer sur une corde (les deux suivants font la même chose):
$data['discount'] = (string) $data['discount'];
$data['discount'] = '' . $data['discount'];
pour mon cas d'utilisation ce fut une solution rapide et efficace. Notez juste que cela signifie que lorsque vous le décodez en arrière de JSON il sera sois une ficelle car elle sera entourée de doubles guillemets.