国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

PHP7 serialize_precision 配置不當導致 json_encode() 浮點小數

zhangyucha0 / 2548人閱讀

摘要:感謝地獄星星原因已找到該現象只出現在版本上建議使用默認值即可參考事情是這樣

感謝 @地獄星星:
原因已找到, 該現象只出現在PHP 7.1+版本上
建議使用默認值 serialize_precision = -1 即可
參考: https://wiki.php.net/rfc/prec...
----------------------------------------------------------------------------------

事情是這樣的,項目里發現一個奇怪的現象,json_encode一個帶浮點價格的數據, 出現溢出, 比如:


這明顯是不能接受的, 數據雖然很接近, 但畢竟已經變更了
下意識地認為這是php的一個bug, 不能準確地json序列化一個浮點小數
這個問題google了半天竟然也無果, 然后我跟同事說, 你們json_encode數據里有小數的時候, 記得先number_format()轉化成字符串.

自己又寫了個fix方法, 遍歷數據, 把is_float()的數據都用number_format()轉化了

function json_encode_pre($d, $depth=128, $level=0){
    if($level>$depth) return $d;
    if(is_array($d)){
        foreach ($d as $i => $v) { $d[$i] = json_encode_pre($v, $depth, $level+1); }
        return $d;
    }
    if(is_float($d)){
        # 測試發現number_format有效數字低于18(保守取16)時,不會溢出
        $p = 16 - strlen(intval($d));
        $f = number_format($d, $p);
        if($p>1){ $f = preg_replace("/0+$/","", $d); }
        return $d;
    }
    return $d;
}

echo number_format(277.2, 14); // 當18位有效數字處理(277.2已有4位有效數字)
// 277.199999999999989
echo number_format(277.2, 12); // 當16位
// 277.2000000000000
echo json_encode(json_encode_pre(277.2));
// "277.2"

看到這結果時, 便猜測是有效數字位數的問題導致了溢出, PHP怎么會有這么蠢的設計呢?這是我當時的想法.

然后想著是不是能從源碼下手, 于是查了下php源碼, 發現這段代碼:

static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */
{
    size_t len;
    char num[PHP_DOUBLE_MAX_LENGTH];

    php_gcvt(d, (int)PG(serialize_precision), ".", "e", num);
    len = strlen(num);
    if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, ".") == NULL && len < PHP_DOUBLE_MAX_LENGTH - 2) {
        num[len++] = ".";
        num[len++] = "0";
        num[len] = "