PHP NumberFormatter и Currency, не может установить точность

Я хочу установить точность 0 при использовании класса PHP NumberFormatter (из расширения Intl ) с валютой. Однако у меня есть какой-то странный результат. Вот:

$numberFormatter = new NumberFormatter('en-US', NumberFormatter::CURRENCY); $numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 0); echo $numberFormatter->formatCurrency('45', 'USD'); 

Он выдает $45 , чего я хочу. Однако, если я изменю валюту на EUR с теми же настройками:

 echo $numberFormatter->formatCurrency('45', 'EUR'); 

Он выводит €45.00 (хотя я явно настроен на точность нуля).

Еще более странно, если я установил locale в fr-FR , он выведет число, как ожидалось:

 $numberFormatter = new NumberFormatter('fr-FR', NumberFormatter::CURRENCY); $numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 0); echo $numberFormatter->formatCurrency('45', 'EUR'); 

Он выводит 45 € .

Это ошибка?

Майкл Гальего забыл обновить эту проблему. Проверьте его отчет об ошибке и ответы на php.net.

[2012-10-05 08:21 UTC] jpauli @ email.com

Я подтверждаю, что это ошибка ICU в ветке 4.4.x.
Рассмотрите возможность обновления libicu, 4.8.x дает правильный результат

Эта функция использует информацию локали для форматирования числа в валюте, формат, который я использую, – «% # 10n» для $:

 /** * That it is an implementation of the function money_format for the * platforms that do not it bear. * The function accepts to same string of format accepts for the * original function of the PHP. * The function is tested using PHP 5.1.4 in Windows XP * and Apache WebServer. * * format I am are using is '%#10n' for $; * */ public static function money_format( $format, $number ) { $regex = '/%((?:[\^!\-]|\+|\(|\=.)*)([0-9]+)?'. '(?:#([0-9]+))?(?:\.([0-9]+))?([in%])/'; if (setlocale(LC_MONETARY, 0) == 'C') { setlocale(LC_MONETARY, ''); } $locale = localeconv(); preg_match_all($regex, $format, $matches, PREG_SET_ORDER); foreach ($matches as $fmatch) { $value = floatval($number); $flags = array( 'fillchar' => preg_match('/\=(.)/', $fmatch[1], $match) ? $match[1] : ' ', 'nogroup' => preg_match('/\^/', $fmatch[1]) > 0, 'usesignal' => preg_match('/\+|\(/', $fmatch[1], $match) ? $match[0] : '+', 'nosimbol' => preg_match('/\!/', $fmatch[1]) > 0, 'isleft' => preg_match('/\-/', $fmatch[1]) > 0 ); $width = trim($fmatch[2]) ? (int)$fmatch[2] : 0; $left = trim($fmatch[3]) ? (int)$fmatch[3] : 0; $right = trim($fmatch[4]) ? (int)$fmatch[4] : $locale['int_frac_digits']; $conversion = $fmatch[5]; $positive = true; if ($value < 0) { $positive = false; $value *= -1; } $letter = $positive ? 'p' : 'n'; $prefix = $suffix = $cprefix = $csuffix = $signal = ''; $signal = $positive ? $locale['positive_sign'] : $locale['negative_sign']; switch (true) { case $locale["{$letter}_sign_posn"] == 1 && $flags['usesignal'] == '+': $prefix = $signal; break; case $locale["{$letter}_sign_posn"] == 2 && $flags['usesignal'] == '+': $suffix = $signal; break; case $locale["{$letter}_sign_posn"] == 3 && $flags['usesignal'] == '+': $cprefix = $signal; break; case $locale["{$letter}_sign_posn"] == 4 && $flags['usesignal'] == '+': $csuffix = $signal; break; case $flags['usesignal'] == '(': case $locale["{$letter}_sign_posn"] == 0: $prefix = '('; $suffix = ')'; break; } if (!$flags['nosimbol']) { $currency = $cprefix . ($conversion == 'i' ? $locale['int_curr_symbol'] : $locale['currency_symbol']) . $csuffix; } else { $currency = ''; } $space = $locale["{$letter}_sep_by_space"] ? ' ' : ''; $value = number_format($value, $right, $locale['mon_decimal_point'], $flags['nogroup'] ? '' : $locale['mon_thousands_sep']); $value = @explode($locale['mon_decimal_point'], $value); $n = strlen($prefix) + strlen($currency) + strlen($value[0]); if ($left > 0 && $left > $n) { $value[0] = str_repeat($flags['fillchar'], $left - $n) . $value[0]; } $value = implode($locale['mon_decimal_point'], $value); if ($locale["{$letter}_cs_precedes"]) { $value = $prefix . $currency . $space . $value . $suffix; } else { $value = $prefix . $value . $space . $currency . $suffix; } if ($width > 0) { $value = str_pad($value, $width, $flags['fillchar'], $flags['isleft'] ? STR_PAD_RIGHT : STR_PAD_LEFT); } $format = str_replace($fmatch[0], $value, $format); } return $format; } 

Вы должны предоставить правильную комбинацию языка и валюты. Например, fr-FR / fr-bh / fr-ch support €, что и должно быть предусмотрено в функции formatCurrency.

Я думаю, вы должны использовать локаль, которая поддерживает валюту назначения. Так что у en_US нет евро. de_DE есть и fr_FR. Так что не странно, что fr_FR поддерживает Евро.

Кажется, что это не ошибка.

Задайте значение локали по умолчанию в php ini, которое вы можете использовать:

ini_set ('intl.default_locale', 'de-DE');

Чтобы изменить формат номера, используйте:

setlocale (LC_MONETARY, 'de-DE');

Вы можете использовать следующую строку кода для форматирования денег: –

 $number = 1234.56; setlocale(LC_MONETARY,"en_US"); // Sets the Default for money echo money_format("%i", $number); 

Он выведет вас:

 USD 1,234.56