number_format($number, $decimals) 把数字转成带千位分隔符、小数位固定的字符串:number_format(1234567.891, 2) 返回 "1,234,567.89"。只传一个参数时,它会舍入到整数:number_format(1234567.891) 是 "1,234,568"。
四个参数
number_format(
float $num,
int $decimals = 0,
?string $decimal_separator = ".",
?string $thousands_separator = ","
): string
第三个参数是整数部分和小数之间的字符,第四个参数是每三位数字之间的字符。两者都可以是任意字符串,包括空字符串或多字节字符。修改下面的分隔符,看看每种格式的效果:
区域数据(CLDR)中,法语使用窄不换行空格(U+202F),俄语使用不换行空格(U+00A0),这样数字就不会被拆到两行。在 HTML 中,用 "\u{202F}" 或 "\u{00A0}" 作为分隔符,而不是普通空格。
不带千位分隔符的格式化
第四个参数传 ''。这样得到的是小数位固定的纯数字,正是支付网关、CSV 导出和 <input type="number"> 的值所需要的格式:
最后一行中,先 round() 再强制转换很重要:19.9 * 100 实际存储的是 1989.9999999999998,只用 (int) 会把它截成 1989。
number_format 怎么舍入
number_format() 和 round() 一样,按“远离零的一半进位”舍入,所以 0.5 变成 1,-2.5 变成 -3。它还会纠正 2.675 这类值中微小的二进制误差,这就是它的结果可能和 sprintf('%.2f') 不同的原因:
2.675 无法在二进制中精确存储,实际存储的值比它略小一点。sprintf() 格式化的是这个存储值,得到 2.67;而 number_format() 和 round() 把它当作你写下的 2.675。如果需要特定的舍入规则,先自己调用 round()、floor() 或 ceil()(参见舍入与数学函数),再把结果传给 number_format()。
格式化金额和其他货币
number_format() 对货币一无所知,所以货币符号要你自己加。负号要放在符号前面,另外别忘了日元没有小数:
如果需要按地区输出,让每个国家的货币符号都出现在正确的位置,intl 扩展的 NumberFormatter 可以一手包办:
$fmt = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(1234.5, 'EUR'); // 1.234,50 € (a no-break space before €)
它依赖 intl 扩展,而这个扩展并非到处都有安装,所以 number_format() 加上你自己的符号是可移植性更好的选择。
结果是字符串,不是数字
这是使用 number_format() 时最常见的 bug:先格式化一个值,再拿它做计算。"1,234.50" 不是数字字符串,所以 PHP 只会读取逗号前面的 1:
<?php
echo number_format(1234.5, 2) + 1;
Warning: A non-numeric value encountered in /home/index.php on line 2
2
把这样的字符串再传回 number_format() 更糟:它会抛出 TypeError: number_format(): Argument #1 ($num) must be of type int|float, string given。计算时保留原始数字,只在输出的那一刻再格式化。如果你从表单或文件中拿到的是已经格式化的字符串,先去掉分隔符:
如果要补齐位数、对齐,或者在数字前加正号,改用 sprintf();它不会添加千位分隔符,但可以控制宽度和符号。
常见问题
PHP 中怎么用逗号分隔数字的千位?
调用 number_format($n):number_format(1234567) 返回 "1,234,567"。第二个参数指定小数位:number_format(1234567.891, 2) 返回 "1,234,567.89"。
怎么让 number_format 不带逗号?
把千位分隔符设为空字符串:number_format(1234.5, 2, '.', '') 返回 "1234.50"。支付接口和 CSV 文件通常要的就是这种格式。
number_format 是四舍五入还是直接截断?
它会舍入,规则是“远离零的一半进位”:number_format(2.5) 是 "3",number_format(-2.5) 是 "-3",number_format(2.675, 2) 是 "2.68"。如果想直接截掉多余的小数,先用 floor():number_format(floor(2.679 * 100) / 100, 2) 得到 "2.67"。
怎么按欧洲格式(1.234,56)显示数字?
用第三和第四个参数交换两种分隔符:number_format(1234.56, 2, ',', '.') 返回 "1.234,56"。法国和瑞士的格式把第四个参数换成空格或撇号即可。
为什么对 number_format 的结果做加法会算错?
number_format() 返回的是 "1,234.50" 这样的字符串,用它做数学运算时,PHP 只会读取逗号前面的 1。计算时保留原始数字,只在输出时才调用 number_format()。