money_format

(PHP 4 >= 4.3.0, PHP 5, PHP 7)

money_format将数字格式化为货币字符串

警告

此函数自 PHP 7.4.0 起已弃用,自 PHP 8.0.0 起移除。强烈建议不要依赖此函数。

说明

money_format(string $format, float $number): string

money_format() 返回number的格式化版本。此函数包装了 C 库函数strfmon(),不同之处在于此实现一次仅转换一个数字。

参数

format

格式规范由以下序列组成

  • 一个%字符

  • 可选标志

  • 可选字段宽度

  • 可选左精度

  • 可选右精度

  • 一个必需的转换字符

标志

可以使用以下可选标志中的一个或多个

=f

字符=后跟一个(单字节)字符f,用作数字填充字符。默认填充字符为空格。

^

禁用分组字符的使用(由当前区域设置定义)。

+(

指定正数和负数的格式样式。如果使用+,则将使用区域设置的+-等效项。如果使用(,则负数用括号括起来。如果没有给出规范,则默认为+

!

从输出字符串中抑制货币符号。

-

如果存在,它将使所有字段左对齐(向右填充),而不是默认的向右对齐(向左填充)。

字段宽度

w

一个十进制数字字符串,指定最小字段宽度。除非使用标志-,否则字段将右对齐。默认值为 0(零)。

左精度

#n

预期出现在小数点左侧的数字的最大位数(n)(例如,小数点)。它通常用于使用填充字符使格式化输出保持在相同的列中,如果数字位数小于n。如果实际数字位数大于n,则忽略此规范。

如果未使用^标志抑制分组,则在添加任何填充字符(如果有)之前将插入分组分隔符。分组分隔符不会应用于填充字符,即使填充字符是数字也是如此。

为了确保对齐,格式化输出中出现在数字之前或之后的任何字符(如货币或符号符号)都将根据需要用空格字符填充,以使它们的正负格式具有相等的长度。

右精度

.p

一个句点,后跟小数点后数字的位数(p)。如果p的值为 0(零),则将省略小数点及其右侧的数字。如果没有包含右精度,则默认将由当前使用的区域设置决定。在格式化之前,将要格式化的金额四舍五入到指定的位数。

转换字符

i

数字将根据区域设置的国际货币格式进行格式化(例如,对于美国区域设置:USD 1,234.56)。

n

数字将根据区域设置的国家货币格式进行格式化(例如,对于 de_DE 区域设置:EU1.234,56)。

%

返回%字符。

number

要格式化的数字。

返回值

返回格式化的字符串。格式化字符串之前和之后的字符将保持不变。非数字number导致返回null并发出E_WARNING

变更日志

版本 说明
7.4.0 此函数已弃用。改为使用NumberFormatter::formatCurrency().

示例

示例 #1 money_format() 示例

我们将使用不同的区域设置和格式规范来说明此函数的使用。

<?php

$number
= 1234.56;

// 让我们打印 en_US 区域设置的国际格式
setlocale(LC_MONETARY, 'en_US');
echo
money_format('%i', $number) . "\n";
// USD 1,234.56

// 意大利国家格式,保留两位小数`
setlocale(LC_MONETARY, 'it_IT');
echo
money_format('%.2n', $number) . "\n";
// Eu 1.234,56

// 使用负数
$number = -1234.5672;

// 美国国家格式,对负数使用 ()
// 以及 10 位左精度
setlocale(LC_MONETARY, 'en_US');
echo
money_format('%(#10n', $number) . "\n";
// ($ 1,234.57)

// 与上面的格式类似,添加使用 2 位右
// 精度和 '*' 作为填充字符
echo money_format('%=*(#10.2n', $number) . "\n";
// ($********1,234.57)

// 让我们左对齐,宽度为 14 位,左精度为 8 位
// 右精度为 2 位,不使用分组字符
// 并使用 de_DE 区域设置的国际格式。
setlocale(LC_MONETARY, 'de_DE');
echo
money_format('%=*^-14#8.2i', 1234.56) . "\n";
// Eu 1234,56****

// 让我们在转换规范之前和之后添加一些文字
setlocale(LC_MONETARY, 'en_GB');
$fmt = 'The final value is %i (after a 10%% discount)';
echo
money_format($fmt, 1234.56) . "\n";
// The final value is GBP 1,234.56 (after a 10% discount)

?>

注释

注意:

函数money_format()仅在系统具有 strfmon 功能时才定义。例如,Windows 没有,因此money_format()在 Windows 中未定义。

注意:

区域设置设置的LC_MONETARY类别会影响此函数的行为。在使用此函数之前,使用setlocale()设置为适当的默认区域设置。

参见

添加说明

用户贡献的说明 16 个说明

tim
9 年前
对于我们大多数美国人来说,我们不希望看到我们的货币符号是“USD”,所以“%i”不符合要求。以下是我使用的有效方法,可以获得大多数人希望看到的数字格式。

$number = 123.4
setlocale(LC_MONETARY, 'en_US.UTF-8');
money_format('%.2n', $number);

输出
$123.40

这会在开头给我一个美元符号,并在结尾给我两位数字。
Rafael M. Salvioni
15 年前
这是之前发布的某个函数,但已修复了各种错误。

感谢 Stuart Roe 报告了关于打印信号的错误。

<?php
/*
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.

(Sorry. my writing in English is very bad)

The function is tested using PHP 5.1.4 in Windows XP
and Apache WebServer.
*/
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;
}

?>
todoventas at xarxa-cat dot net
10 年前
在我的运行 PHP 5.4.13 的 Windows XP SP3 上,Rafael M. Salvioni 函数 localeconv(); 返回了一个无效的数组,因此为了防止出现警告消息:implode(): Invalid arguments passed,我只需手动添加 $locale。对于其他语言,只需使用正确的设置填充数组即可。

<?

$locale = array(
'decimal_point' => '.',
'thousands_sep' => '',
'int_curr_symbol' => 'EUR',
'currency_symbol' => '€',
'mon_decimal_point' => ',',
'mon_thousands_sep' => '.',
'positive_sign' => '',
'negative_sign' => '-',
'int_frac_digits' => 2,
'frac_digits' => 2,
'p_cs_precedes' => 0,
'p_sep_by_space' => 1,
'p_sign_posn' => 1,
'n_sign_posn' => 1,
'grouping' => array(),
'mon_grouping' => array(0 => 3, 1 => 3)

);
?>
jeremy
15 年前
如果 money_format 似乎无法正常工作,请确保您定义了有效的区域设置。例如,在 Debian 上,“en_US”不是有效的区域设置 - 您需要“en_US.UTF-8”或“en_US.ISO-8559-1”。

这让我沮丧了一段时间。Debian 在 /usr/share/i18n/SUPPORTED 中有一个有效的区域设置列表;如果它无法正常工作,请在那里找到您的区域设置。
jsb17NO at SPAMcornell dot edu
11 年前
要删除零值小数,请使用以下方法
<?php
/*
与 php number_format() 相同,但如果以 .0、.00、.000 等结尾,则完全删除小数
返回字符串类型,四舍五入的数字 - 与 php number_format() 相同):
示例:
number_format_drop_zero_decimals(54.378, 2) ==> '54.38'
number_format_drop_zero_decimals(54.00, 2) ==> '54'
*/
function number_format_drop_zero_decimals($n, $n_decimals)
{
return ((
floor($n) == round($n, $n_decimals)) ? number_format($n) : number_format($n, $n_decimals));
}
?>
结果
number_format_drop_zero_decimals(54.377, 2) ==> 54.38
number_format_drop_zero_decimals('54.377', 2) ==> 54.38
number_format_drop_zero_decimals(54.377, 3) ==> 54.377
number_format_drop_zero_decimals(54.007, 2) ==> 54.01
number_format_drop_zero_decimals(54.000, 2) ==> 54
number_format_drop_zero_decimals(54.00, 2) ==> 54
number_format_drop_zero_decimals(54.0, 2) ==> 54
number_format_drop_zero_decimals(54.1, 2) ==> 54.10
number_format_drop_zero_decimals(54., 2) ==> 54
number_format_drop_zero_decimals(54, 2) ==> 54
number_format_drop_zero_decimals(54, 3) ==> 54
number_format_drop_zero_decimals(54 + .13, 2) ==> 54.13
number_format_drop_zero_decimals(54 + .00, 2) ==> 54
number_format_drop_zero_decimals(54.0007, 4) ==> 54.0007
number_format_drop_zero_decimals(54.0007, 3) ==> 54.001
number_format_drop_zero_decimals(54.00007, 3) ==> 54 // 注意
~B
11 年前
我们发现,在从 Ubuntu 10.04 php -v 5.3.2 切换到 Ubuntu 12.04 php -v 5.3.10 之后,这不再起作用

<?php setlocale(LC_MONETARY, 'en_US'); ?>

发现使用

<?php setlocale(LC_MONETARY, 'en_US.UTF-8'); ?>

效果很好
andrey.dobrozhanskiy [-a-t-] gmail com
14 年前
此函数使用逗号将整数值分隔开。例如

<?php
echo formatMoney(1050); # 1,050
echo formatMoney(1321435.4, true); # 1,321,435.40
echo formatMoney(10059240.42941, true); # 10,059,240.43
echo formatMoney(13245); # 13,245

function formatMoney($number, $fractional=false) {
if (
$fractional) {
$number = sprintf('%.2f', $number);
}
while (
true) {
$replaced = preg_replace('/(-?\d+)(\d\d\d)/', '$1,$2', $number);
if (
$replaced != $number) {
$number = $replaced;
} else {
break;
}
}
return
$number;
}
?>
Felix Duterloo
8 年前
对 Rafael M. Salvioni 的 Windows money_format 解决方案的改进:当在格式化中未选择货币符号时,如果区域设置将其放置在位置 3 或 4,则减号也会丢失。将 $currency = ''; 更改为:$currency = $cprefix .$csuffix;

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 = $cprefix .$csuffix;
}
$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;
}
richard dot selby at uk dot clara dot net
18 年前
仔细检查您的代码计划运行的任何版本的 PHP 是否定义了 money_format()。您可能会感到惊讶。

例如,它在我的用于编写代码的 Linux 机器上工作,但在运行 BSD 4.11 变体的服务器上却无法工作。(这可能是因为 strfmon 未定义 - 请参阅本页顶部的说明)。这不仅仅是 Windows/Unix 问题。
Anonymous
10 个月前
Rafael M. Salvioni 的代码在值为正且提供的格式包含 ( 标记时存在一个小错误。当值为负时,值应该只用括号括起来。这应该可以解决问题

<?php
if (!function_exists('money_format'))
{
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'] == '(' && !$positive:
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;
}
}
?>
phpdeveloperbalaji at gmail dot com
12 年前
您好,

对于南亚货币,此函数可能很方便。

它将处理负数以及浮点数(派萨)。

<?php
function my_money_format($number)
{
if(
strstr($number,"-"))
{
$number = str_replace("-","",$number);
$negative = "-";
}

$split_number = @explode(".",$number);

$rupee = $split_number[0];
$paise = @$split_number[1];

if(@
strlen($rupee)>3)
{
$hundreds = substr($rupee,strlen($rupee)-3);
$thousands_in_reverse = strrev(substr($rupee,0,strlen($rupee)-3));
for(
$i=0; $i<(strlen($thousands_in_reverse)); $i=$i+2)
{
$thousands .= $thousands_in_reverse[$i].$thousands_in_reverse[$i+1].",";
}
$thousands = strrev(trim($thousands,","));
$formatted_rupee = $thousands.",".$hundreds;

}
else
{
$formatted_rupee = $rupee;
}

if((int)
$paise>0)
{
$formatted_paise = ".".substr($paise,0,2);
}

return
$negative.$formatted_rupee.$formatted_paise;

}
?>

谢谢,
swapnet
16 年前
考虑格式化一些南亚国家使用的货币,这些国家使用 ##,##,###.## 货币格式。
以下代码生成类似 Rs. 4,54,234.00 的内容。

<?php
function convertcash($num, $currency){
if(
strlen($num)>3){
$lastthree = substr($num, strlen($num)-3, strlen($num));
$restunits = substr($num, 0, strlen($num)-3); // 提取最后三位数字
$restunits = (strlen($restunits)%2 == 1)?"0".$restunits:$restunits; // 将剩余的数字以 2 为单位分组,并在开头添加一个 0 以保持 2 的分组。

$expunit = str_split($restunits, 2);
for(
$i=0; $i<sizeof($expunit); $i++){
$explrestunits .= (int)$expunit[$i].","; // 创建每个 2 位的组,并在末尾添加一个逗号
}

$thecash = $explrestunits.$lastthree;
} else {
$thecash = $convertnum;
}

return
$currency.$thecash.".00"; // 写入最终格式,其中 $currency 是货币符号。
}
?>

现在,调用函数,如 convertcash($row['price'], 'Rs '); // 这是从数据库中调用的价格,使用印度卢比前缀,价格必须是纯数字格式,例如 454234。
kaigillmann at googlemail dot com
10 年前
如果你得到 "EUR" 而不是欧元符号,将区域设置设置为 utf8 字符集,如下所示

<?php
setlocale
(LC_MONETARY, 'de_DE.utf8');
echo
money_format('%+n', 1234.56);
?>
scot from ezyauctionz.co.nz
16 年前
这是我刚写的一段实用的代码,因为我找不到任何其他适合我情况的代码。
这将处理用户传递给脚本的货币值,重新格式化任何逗号的使用,以便在通过检查浮点数的输入验证系统时不会被破坏。

它不是万无一失的,但将处理大多数用户输入的常见输入,例如 1,234,567(输出 1234567)或 1,234.00(输出 1234.00),甚至处理 12,34(输出 12.34),我预计它可以处理负数,但没有测试,因为在我的情况下没有使用它。

当其他选项(如 money_format())不适合或不可用时,这很有效。

<?php
///////////////
// BEGIN CODE 将所有价格金额转换为格式良好的值
function converttonum($convertnum,$fieldinput){
$bits = explode(",",$convertnum); // 将输入值拆分为允许检查的元素

$first = strlen($bits[0]); // 获取第一个逗号之前的部分(千位/百万位)
$last = strlen($bits[1]); // 获取第一个逗号之后的部分(千位(如果用户错误地使用,则为小数位)

if ($last <3){ // 检查逗号是否用作小数点
$convertnum = str_replace(",",".",$convertnum);
}
else{
// 假设逗号是千位分隔符,因此将其删除
$convertnum = str_replace(",","",$convertnum);
}

$_POST[$fieldinput] = $convertnum; // 重新定义变量的值,使其成为新的更正值
}

@
converttonum($_POST[inputone],"inputone");
@
converttonum($_POST[inputtwo],"inputtwo");
@
converttonum($_POST[inputthree],"inputthree");
// END CODE
//////////////

?>

这适用于英语用法,可能需要调整才能适用于其他类型。
justsomeone
7 年前
使用带有超过两位小数的浮点值的 money_format 函数可能会导致舍入误差。
也许此函数将帮助您避免这些故障

<?php
// 一个基础价格为 12.95 的产品
$price = 1295;

// 数量也是一个整数,但翻译后应该是 11.91
$quantity = 1191;

// 结果: 154.2345
// 与 12.95 * 11.91 相同
$sum = ($price / 100) * ($quantity /100);

// 错误结果: 154.23
money_format('%!i', $sum);

// 错误结果: 154.23
number_format($sum, 2);

// 错误结果: 154.23
bcmul($price / 100, $quantity / 100, 2);

// 正确结果 : 154.24
money_format_rounded('%!i', $sum);

/**
* 将数字格式化为货币字符串。将每个小数位四舍五入到定义的精度。
*
* @param string $format money_format 函数的格式
* @param float|int|string $number 要格式化的数字
* @param int $maxPrecision 四舍五入到 $maxPrecision 个小数位。默认值为: 2
* @param int $roundingType round 函数的舍入类型。默认值为: \PHP_ROUND_HALF_UP
*
* @return string
*/
function money_format_rounded($format, $number, $maxPrecision = 2, $roundingType = \PHP_ROUND_HALF_UP)
{
$strlen = strlen($number);
if (
$strlen === 0) {
return
money_format($format, $number);
}

$length = $strlen - strrpos($number, '.') - 1;
if (
$length <= 0) {
return
money_format($format, $number);
}

$rounded = $number;
for (
$i = --$length; $i >= $maxPrecision; $i--) {
$rounded = round($rounded, $i, $roundingType);
}

return
money_format($format, $rounded);
}
sainthyoga2003 at gmail dot com
4 年前
请注意,从 PHP 7.3 开始,此方法已弃用,从 PHP 7.4 开始,此方法将触发弃用错误,因此,请将您的 PHP Web 服务器设置为不跟踪 E_DEPRECATED 错误报告。
To Top