Number::percentage
Formats a value as a locale-aware percentage string, treating 12.5 as 12.5%.
Number::percentage(int|float $number, int $precision = 0, ?int $maxPrecision = null, ?string $locale = null): string|false- Added in Laravel 10.33.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$$number | int|float | The percentage value itself — 12.5 means 12.5%, not 1250%. |
$$precisionoptional | int= 0 | Exact fraction digits, padded with zeros. |
$$maxPrecisionoptional | ?int= null | Upper bound on fraction digits. Takes priority over $precision. |
$$localeoptional | ?string= null | ICU locale controlling the decimal separator and sign placement. |
Return value
string|falseThe formatted percentage string including the percent sign, or false on formatter failure.
Errors
Throws RuntimeException when the intl PHP extension is not loaded.
Changelog
- PHP 10.33.0Introduced together with the Illuminate\Support\Number class.
Number::percentage() renders a percentage with the sign attached and the decimal separator taken from the locale. The one thing to internalise: it divides your argument by 100 before handing it to ICU's percent formatter, which multiplies by 100 again. The two cancel out, so you pass the human-readable percentage. Number::percentage(10) is 10%. If you have a ratio like 0.125 from $converted / $visitors, multiply it by 100 yourself first.
Precision behaves like format()
The default precision of 0 means a bare 10%, not 10.0%. Pass precision: 2 to pad to a fixed width for a table column, or maxPrecision: 2 to cap the digits without padding. As on Number::format(), maxPrecision is checked first and wins outright when both are supplied.
Rounding is display-only
With the default precision, anything from 9.5 to 10.4 comes out as 10%. A dashboard showing several rounded shares can easily print four numbers that read as 101%. Round once into the values you intend to display, or show one decimal, rather than trusting the formatter to reconcile them.
Example
When to use it
- Rendering a conversion rate in an analytics panel with one decimal place
- Showing a discount badge as a whole-number percentage
- Formatting a job's completion share in a German locale where the separator is a comma
Frequently asked questions
Why does Number::percentage(0.125) return 0%?
Because the method expects the percentage, not the ratio. It divides by 100 internally, so 0.125 is read as one eighth of one percent and rounds to 0% at the default precision. Pass 12.5 instead.
How do I show one decimal place instead of a whole number?
Pass precision: 1 to always show one digit, or maxPrecision: 1 to show it only when it is non-zero. The default precision of 0 rounds everything to a whole percent.
Why do my percentages add up to 99% or 101%?
Each value is rounded independently for display, so the rounded parts need not sum to the rounded whole. Show more decimals, or calculate the final row as 100 minus the others rather than from its own share.
More examples
Rounded shares that do not add up
Each third rounds up to 33%, and the column sums to 99% rather than 100%. Nothing is broken — this is what rounding three equal shares to whole numbers does. Either show a decimal, or compute the last row as the remainder of the others.
<?php
use Illuminate\Support\Number;
$counts = ['direct' => 1, 'search' => 1, 'social' => 1];
$total = array_sum($counts);
foreach ($counts as $source => $count) {
printf("%-7s %s\n", $source, Number::percentage($count / $total * 100));
}A period-over-period change
Prints +20%, then -16.7%, then an em dash. The negative sign comes from the formatter itself; only the plus has to be added by hand. maxPrecision: 1 keeps +20% clean instead of padding it to +20.0%.
<?php
use Illuminate\Support\Number;
function change(float $previous, float $current): string
{
if ($previous == 0.0) {
return '—';
}
$delta = ($current - $previous) / $previous * 100;
return ($delta >= 0 ? '+' : '').Number::percentage($delta, maxPrecision: 1);
}
echo change(1200, 1440), PHP_EOL;
echo change(1440, 1200), PHP_EOL;
echo change(0, 500), PHP_EOL;Locale-sensitive output
English uses a dot and a tight sign; German and French use a comma, and several European locales insert a non-breaking space before the sign. Assert against the formatter's output rather than a hand-typed string when testing localised views.
<?php
use Illuminate\Support\Number;
foreach (['en', 'de', 'fr', 'tr'] as $locale) {
printf("%-3s %s\n", $locale, Number::percentage(12.5, precision: 2, locale: $locale));
}
Discussion