number_format
Formats a number with grouped thousands and a fixed number of decimal places.
number_format(float $num, int $decimals = 0, ?string $decimal_separator = ".", ?string $thousands_separator = ","): string- Added in PHP 4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$num | float | The number being formatted. |
$decimalsoptional | int= 0 | Number of decimal digits. If 0, the decimal separator is omitted. As of PHP 8.3, negative values round num to significant digits before the decimal point. |
$decimal_separatoroptional | ?string= "." | The separator placed before the decimal digits. |
$thousands_separatoroptional | ?string= "," | The separator placed between groups of three digits. |
Return value
stringA formatted string version of num.
Changelog
- PHP 8.3.0Negative values for decimals are now handled, rounding num to significant digits before the decimal point.
- PHP 8.0.0Prior to this version, number_format() accepted one, two or four arguments, but not three.
- PHP 7.2.0No longer returns "-0"; previously values such as -0.01 could format as -0.
number_format turns a float into a display string: it rounds to the requested number of decimals, pads with zeros if needed, and inserts a grouping separator every three digits. It is the fastest way to render prices, totals and counts in a table without dragging in intl.
Locale is your job
The function has no locale awareness at all. The defaults are US-style — . for decimals, , for thousands — and if you need German (1.234.567,89) or French (1 234 567,89) you pass those separators yourself. When you need genuine per-locale formatting, currency symbols and correct grouping for languages that do not group in threes, use NumberFormatter from the intl extension instead.
Rounding, and what comes back
Rounding is half-up on the value as stored, so ordinary float imprecision applies; if the exact cent matters, keep money in integer minor units and only format at the very end. Since PHP 8.3 a negative decimals rounds to the left of the decimal point — number_format(12345, -3) gives 12,000. Since PHP 7.2 a value like -0.01 formats as 0.0 rather than the confusing -0.0.
The return value is a string. Feeding it back into arithmetic is the number-one bug here: the thousands separator makes the numeric cast stop at the comma.
Example
When to use it
- Render order totals as "1,234.50" in an invoice table.
- Format the same figure for a German or French locale by swapping the separator arguments.
- Show large view or follower counts with thousands grouping in a dashboard.
Frequently asked questions
Why does number_format return the wrong value when I add to it?
Because it returns a string containing separators, and PHP's numeric cast stops at the first comma — "1,234.50" becomes 1. Do all arithmetic on the raw float and format only at output time.
How do I format a number for a European locale?
Pass the separators explicitly: number_format($n, 2, ',', '.') gives 1.234.567,89. number_format itself ignores setlocale, so for real locale-driven output use the intl extension's NumberFormatter class.
What is the difference between number_format and sprintf with %.2f?
sprintf('%.2f', $n) fixes the decimal places but adds no thousands separator and always uses a dot. number_format does both grouping and decimals, and lets you choose the separator characters.
More examples
Aligning a price column
Prints a padded table ending in `9.99` and `1,249.50`. number_format supplies the trailing zero and the thousands comma, printf handles the column widths. Note the price is passed with %s, not %f — it is already a string by then, and %f would re-format it and mangle the comma.
<?php
$rows = [['Widget', 4, 9.99], ['Gizmo', 120, 1249.5]];
foreach ($rows as [$name, $qty, $price]) {
printf("%-8s %5s %10s\n", $name, number_format($qty), number_format($price, 2));
}Negative decimals, and the string trap
`12,000` shows the PHP 8.3 negative-decimals rounding; `0.0` shows the PHP 7.2 change that stops -0 appearing. Then the trap: the formatted value is the string "1,234.50", and casting it to float yields 1 because the cast stops at the comma. Strip the separators first to get 1234.5 back.
<?php
echo number_format(12345, -3), PHP_EOL;
echo number_format(-0.01, 1), PHP_EOL;
$formatted = number_format(1234.5, 2);
var_dump($formatted);
var_dump((float) $formatted);
var_dump((float) str_replace(',', '', $formatted));
Discussion