#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 …). Проведя небольшое исследование, вы, вероятно, наткнетесь на этот сайт.
Первоначальная проблема заключается в следующем: другой скрипт, запущенный в том же процессе, что и ваш, изменяет язык во время выполнения вашего скрипта… несмотря на то, что этот другой скрипт может вернуть языковой стандарт к исходному значению, и несмотря на то, что изменение, вероятно, занимает всего лишь долю секунды, оно по-прежнему является общим для всех потоков процесса.
hth
Комментарии:
1. Интересно! Вопрос: потокобезопасная версия php решила бы это?
2. Я перешел на другую модель параллелизма, называемую prefork MPM, и проблема была решена. Спасибо!
3. Нет, потокобезопасность не имеет значения, локаль — это общий ресурс для всего процесса (один поток изменяет его, другие потоки мгновенно видят измененное значение). Я рекомендую прочитать обсуждение phpinternals, очень интересное…