Number::percentage

Formats a value as a locale-aware percentage string, treating 12.5 as 12.5%.

Signature
Number::percentage(int|float $number, int $precision = 0, ?int $maxPrecision = null, ?string $locale = null): string|false
  • Added in Laravel 10.33.0

Parameters

ParameterTypeDescription
$$numberint|floatThe percentage value itself — 12.5 means 12.5%, not 1250%.
$$precisionoptionalint= 0Exact fraction digits, padded with zeros.
$$maxPrecisionoptional?int= nullUpper bound on fraction digits. Takes priority over $precision.
$$localeoptional?string= nullICU 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

Try it yourself
Loading editor…
Press Run to execute the code.

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.

Example · php
<?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%.

Example · php
<?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.

Example · php
<?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

  • Be the first to comment on this lesson.