在金融、電商、報表系統中,將 1234567890 格式化為 1,234,567,890 是基礎需求。本文對比手寫逆序分組算法與內置 number_format()、NumberFormatter 的優劣,給出多場景選型建議。
<?php
/**
* 手寫實現:每 3 位插入逗號(僅供演示,生產請用內置函數)
*/
function splitStrWithComma(string $str): string
{
if (!ctype_digit($str)) {
throw new InvalidArgumentException('輸入必須為純數字字符串');
}
$len = strlen($str);
$parts = [];
for ($i = $len; $i > 0; $i -= 3) {
$start = max(0, $i - 3);
$parts[] = substr($str, $start, $i - $start);
}
return implode(',', array_reverse($parts));
}
echo splitStrWithComma('1234567890'); // 1,234,567,890
| 方案 | 適用場景 | 優點 | 缺點/注意 |
|---|---|---|---|
number_format($num, 0, '.', ',') | 純整數、浮點數定點小數 | 零依賴、極快、行為標準 | 不支援區域化(如印度 1,00,000 格式)、超大整數超出 float 精度 |
NumberFormatter::create('zh_CN', NumberFormatter::DECIMAL) | 國際化、區域化格式、貨幣符號 | ICU 標準、支援所有 CLDR 格式 | 需 intl 擴展、實例化開銷大、字符串輸入需先轉數值 |
sprintf('%0.0f', $num) + 正則 | 極簡場景 | 無額外函數依賴 | 正則易錯、性能差、不推薦 |
| 手寫分組(本文教學版) | 教學、特殊分組邏輯(如 4 位分組) | 完全可控、支援任意長度字符串 | 重複造輪子、易漏邊界、無小數/負號處理 |
<?php
// 1. 簡單整數千分位
$price = 1234567890;
echo number_format($price, 0, '.', ','); // 1,234,567,890
// 2. 保留 2 位小數(金額標準)
$amount = 1234567.891;
echo number_format($amount, 2, '.', ','); // 1,234,567.89
// 3. 國際化:中文區域(萬/億單位)需自定義,NumberFormatter 不直接支援
// 推薦:自行實現中文數字格式化或用專用庫
// 4. 超大整數(超過 53 位精度)必須用字符串處理
$bigInt = '123456789012345678901234567890';
echo splitStrWithComma($bigInt); // 手寫函數支援任意長度
// 5. 貨幣格式化(帶符號、區域化)
$fmt = new NumberFormatter('zh_CN', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(12345.67, 'CNY'); // ¥12,345.67
number_format(12345678901234567890, 0, '.', ',') 會科學計數法丟失精度,大整數務必用字符串或 BCMath/GMP。- 符號,內置函數自動支援。number_format 是四捨五入,貨幣結算常需「銀行家算法」或截斷,請用 BCMath bcdiv 控制。Intl.NumberFormat('zh-CN').format(num) 保持一致。<?php
function formatChineseNumber(int|float|string $num): string
{
$num = (string)$num;
$sign = '';
if ($num[0] === '-') { $sign = '-'; $num = substr($num, 1); }
if (str_contains($num, '.')) { [$int, $dec] = explode('.', $num); } else { $int = $num; $dec = ''; }
$len = strlen($int);
if ($len <= 4) return $sign . $int . ($dec ? ".$dec" : '');
if ($len <= 8) {
$high = substr($int, 0, $len - 4);
$low = substr($int, -4);
return $sign . $high . '萬' . ($low != '0000' ? $low : '') . ($dec ? ".$dec" : '');
}
$yi = substr($int, 0, $len - 8);
$wan = substr($int, $len - 8, 4);
$qian = substr($int, -4);
return $sign . $yi . '億' . ($wan != '0000' ? $wan . '萬' : '') . ($qian != '0000' ? $qian : '') . ($dec ? ".$dec" : '');
}
echo formatChineseNumber(123456789); // 1億2345萬6789
選對工具、守住精度、考慮國際化,數字格式化才能經得起金融級業務的考驗。