PHP — числа с плавающей запятой — проблема с запятой и точкой

#php #double

#php #double

Вопрос:

У меня проблема с моим PHP-сервером (5.6.40). PHP иногда меняет точку на запятую без какого-либо предупреждения.

Например:

 $runTimes = 20;
$number   = 39.102564102564;

for ($i = 0; $i < $runTimes; $i  ) {
    echo "<p>$number</p>";
}
  

Это эхо показывает ‘39.102564102564’, но иногда показывает ‘39,102564102564’ (с запятой). Это ужасно, потому что, когда я вставляю это число в базу данных, оно меняется на 39 (без десятичных знаков).

Я пытался setlocale(LC_NUMERIC, 'C') , но ничего не изменил.

Это происходит не на моем локальном хосте, а только на моем сервере

localeconv() печать:

 Array
(
    [decimal_point] => .
    [thousands_sep] => 
    [int_curr_symbol] => 
    [currency_symbol] => 
    [mon_decimal_point] => 
    [mon_thousands_sep] => 
    [positive_sign] => 
    [negative_sign] => 
    [int_frac_digits] => 127
    [frac_digits] => 127
    [p_cs_precedes] => 127
    [p_sep_by_space] => 127
    [n_cs_precedes] => 127
    [n_sep_by_space] => 127
    [p_sign_posn] => 127
    [n_sign_posn] => 127
    [grouping] => Array
        (
        )

    [mon_grouping] => Array
        (
        )

)
  

Редактировать:

При выполнении скрипта непосредственно через PHP (приглашение) этого не происходит. Эта проблема возникает только через браузер (в данном случае Firefox)

введите описание изображения здесь

РЕШЕНИЕ: я перешел на другую модель параллелизма, называемую prefork MPM, и проблема была решена.

Комментарии:

1. Я подозреваю, что столбец вашей базы данных настроен как INT , что означает, что он всегда будет отбрасывать десятичную дробь. PHP не должен изменять вашу строку с . на , самостоятельно.

2. Нет. Проблема в PHP. Столбец базы данных задается как double .

3. Итак, вы говорите, что ваш первый фрагмент кода иногда выводится с запятой вместо точки?

4. Да, точно…

5. Должно быть, происходит что-то еще… Но я понятия не имею, как вы это выясните.

Ответ №1:

Язык НЕ является потокобезопасным в PHP!

https://www.php.net/manual/en/function.setlocale.php

Информация о локали поддерживается для каждого процесса, а не для каждого потока. Если вы используете PHP на многопоточном серверном API , вы можете столкнуться с внезапными изменениями настроек локали во время выполнения скрипта, хотя сам скрипт никогда не вызывал setlocale(). Это происходит из-за того, что другие сценарии выполняются в разных потоках одного и того же процесса одновременно, изменяя языковой стандарт всего процесса с помощью setlocale(). В Windows информация о локали сохраняется для каждого потока начиная с PHP 5.6.20 и PHP 7.0.5 соответственно.

Что касается вывода (изменение точки и запятой) — это связано с преобразованием числа в строку на уровне C (PHP написан на C …). Проведя небольшое исследование, вы, вероятно, наткнетесь на этот сайт.

https://phpinternals.news/52

Первоначальная проблема заключается в следующем: другой скрипт, запущенный в том же процессе, что и ваш, изменяет язык во время выполнения вашего скрипта… несмотря на то, что этот другой скрипт может вернуть языковой стандарт к исходному значению, и несмотря на то, что изменение, вероятно, занимает всего лишь долю секунды, оно по-прежнему является общим для всех потоков процесса.

hth

Комментарии:

1. Интересно! Вопрос: потокобезопасная версия php решила бы это?

2. Я перешел на другую модель параллелизма, называемую prefork MPM, и проблема была решена. Спасибо!

3. Нет, потокобезопасность не имеет значения, локаль — это общий ресурс для всего процесса (один поток изменяет его, другие потоки мгновенно видят измененное значение). Я рекомендую прочитать обсуждение phpinternals, очень интересное…