number_format($number, $decimals) trả về con số dưới dạng chuỗi, có dấu phân cách hàng nghìn và số chữ số thập phân cố định: number_format(1234567.891, 2) trả về "1,234,567.89". Với một đối số, hàm làm tròn đến số nguyên: number_format(1234567.891) là "1,234,568".
Bốn tham số
number_format(
float $num,
int $decimals = 0,
?string $decimal_separator = ".",
?string $thousands_separator = ","
): string
Tham số thứ ba là ký tự giữa phần nguyên và phần thập phân, tham số thứ tư là ký tự giữa các nhóm ba chữ số. Cả hai có thể là chuỗi bất kỳ, kể cả chuỗi rỗng hay một ký tự nhiều byte. Sửa các dấu phân cách bên dưới để xem từng kiểu; kiểu Việt Nam giống kiểu Đức, number_format($n, 2, ',', '.'):
Dữ liệu locale (CLDR) dùng dấu cách hẹp không ngắt dòng (U+202F) cho tiếng Pháp và dấu cách không ngắt dòng (U+00A0) cho tiếng Nga, để một con số không bao giờ bị tách ra hai dòng. Trong HTML, hãy truyền "\u{202F}" hoặc "\u{00A0}" làm dấu phân cách thay vì dấu cách thường.
Định dạng số không có dấu phân cách hàng nghìn
Truyền '' làm tham số thứ tư. Bạn nhận được một con số thuần với số chữ số thập phân cố định, đúng dạng mà cổng thanh toán, tệp CSV xuất ra và giá trị của <input type="number"> cần:
Ở dòng cuối, round() trước khi ép kiểu là quan trọng: 19.9 * 100 được lưu thành 1989.9999999999998, và chỉ dùng (int) sẽ cắt nó thành 1989.
number_format làm tròn thế nào
number_format() làm tròn giá trị nửa ra xa số 0, giống round(), nên 0.5 thành 1 và -2.5 thành -3. Hàm còn sửa sai số nhị phân rất nhỏ trong các giá trị như 2.675, vì vậy kết quả có thể khác sprintf('%.2f'):
2.675 không lưu chính xác được ở dạng nhị phân; giá trị được lưu nhỏ hơn nó một chút. sprintf() định dạng giá trị được lưu đó và ra 2.67, còn number_format() và round() coi nó là 2.675 như bạn đã viết. Nếu bạn cần một quy tắc làm tròn cụ thể, hãy tự gọi round(), floor() hoặc ceil() trước (xem làm tròn và toán học) rồi truyền kết quả cho number_format().
Định dạng tiền và các loại tiền tệ
number_format() không biết gì về tiền tệ, nên bạn tự thêm ký hiệu. Đặt dấu âm trước ký hiệu, và nhớ rằng yên Nhật không có phần thập phân (tiền đồng Việt Nam cũng vậy):
Để có đầu ra theo locale với vị trí ký hiệu đúng cho từng quốc gia, NumberFormatter của extension intl làm trọn mọi việc:
$fmt = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(1234.5, 'EUR'); // 1.234,50 € (a no-break space before €)
Nó cần extension intl, vốn không được cài ở mọi nơi, nên number_format() kèm ký hiệu tự thêm là lựa chọn chạy được ở khắp nơi.
Kết quả là chuỗi, không phải số
Đây là bug thường gặp nhất với number_format(): định dạng một giá trị rồi tính toán với nó. "1,234.50" không phải chuỗi số, nên PHP chỉ đọc số 1 trước dấu phẩy:
<?php
echo number_format(1234.5, 2) + 1;
Warning: A non-numeric value encountered in /home/index.php on line 2
2
Truyền một chuỗi như vậy trở lại number_format() còn tệ hơn: hàm ném ra TypeError: number_format(): Argument #1 ($num) must be of type int|float, string given. Giữ số gốc để tính toán và chỉ định dạng vào lúc in ra. Nếu bạn nhận một chuỗi đã định dạng từ form hoặc từ tệp, hãy bỏ các dấu phân cách trước:
Để thêm khoảng trắng đệm, căn lề hoặc dấu cộng phía trước con số, hãy dùng sprintf(); hàm này không thêm dấu phân cách hàng nghìn, nhưng điều khiển được độ rộng và dấu.
Câu hỏi thường gặp
Làm sao định dạng số có dấu phẩy phân cách trong PHP?
Gọi number_format($n): number_format(1234567) trả về "1,234,567". Truyền tham số thứ hai cho số chữ số thập phân: number_format(1234567.891, 2) trả về "1,234,567.89".
Làm sao dùng number_format mà không có dấu phẩy?
Truyền chuỗi rỗng làm dấu phân cách hàng nghìn: number_format(1234.5, 2, '.', '') trả về "1234.50". Đây là dạng mà API thanh toán và tệp CSV thường cần.
number_format làm tròn hay cắt bỏ?
Hàm làm tròn, giá trị nửa đi ra xa số 0: number_format(2.5) là "3", number_format(-2.5) là "-3" và number_format(2.675, 2) là "2.68". Để cắt bỏ phần thập phân, hãy dùng floor() trước: number_format(floor(2.679 * 100) / 100, 2) cho ra "2.67".
Làm sao định dạng số kiểu châu Âu hoặc kiểu Việt Nam (1.234,56)?
Đổi chỗ hai dấu phân cách bằng tham số thứ ba và thứ tư: number_format(1234.56, 2, ',', '.') trả về "1.234,56", đúng cách viết số ở Việt Nam. Kiểu Pháp và Thụy Sĩ dùng dấu cách hoặc dấu nháy đơn làm tham số thứ tư.
Vì sao number_format cho kết quả sai khi tôi cộng thêm vào?
number_format() trả về một chuỗi như "1,234.50", và PHP chỉ đọc số 1 trước dấu phẩy khi bạn tính toán với nó. Giữ số gốc để tính toán và chỉ gọi number_format() khi in ra.