Number helpers

Numbers written for people from a page's PHP: grouped with the locale's marks, shortened to 1.5K or 1.5 million, as a place, a percentage or a file size - and kept between bounds. These are the functions of Laravel's Number class, as plain functions. The abbreviate and ordinal pipes do the same in a template.

function what it does
padNumberFormat ( $number, $decimals, $locale ) the number grouped, with exactly so many decimals, the locale's way
padNumberPercentage ( $number, $precision ) 25 as 25%, 25.55 with a precision of 1 as 25.6%, the locale's way
padNumberAbbreviate ( $number, $precision ) 1500 as 2K, or 1.5K with a precision of 1 - K, M, B, T, Q
padNumberForHumans ( $number, $precision ) 1500000 as 2 million, or 1.5 million
padNumberFileSize ( $bytes, $precision ) 1536 as 2 KB, or 1.5 KB - what the bytes pipe answers
padNumberOrdinal ( $number ) 1st, 2nd, 3rd, 4th, 11th, 21st, 112th
padNumberClamp ( $number, $min, $max ) the number, or the bound it went past

Formatting

padNumberFormat writes exactly $decimals decimals, with the thousands grouped and the decimal mark of the locale: the request's $padLocale, or the one given. padNumberPercentage takes a share already counted in hundreds - 25 is 25% - and writes it the locale's way too. Half is rounded up, so 2.5 is 3. PHP's intl extension does the writing when it is there; without it the number is written the plain number_format way.

PHP
fragments/numbers_1.php
HTML
fragments/numbers_1.pad
Result
<?php

// An order total written for the visitor - in the request's
// locale, then in two others - and a share of the sales.

$total = 1234567.891;

$en = padNumberFormat ( $total, 2 );
$nl = padNumberFormat ( $total, 2, 'nl' );
$de = padNumberFormat ( $total, 2, 'de_DE' );

$share = padNumberPercentage ( 25.55, 1 );

?>
<p>{$en} - {$nl} - {$de}</p>
<p>Share of the sales: {$share}</p>

1,234,567.89 - 1.234.567,89 - 1.234.567,89

Share of the sales: 25.6%

Short and readable

padNumberAbbreviate and padNumberForHumans write a large number in thousands, millions, billions, trillions or quadrillions, and padNumberFileSize a byte count in units of 1024. The precision is the most decimals written, the trailing zeros dropped: 1000 with a precision of 1 is 1K. The unit is chosen on the number as it will be written, so 999999 is 1M, not 1000K. Below 1000 the number has no unit, and a size below 1024 is in B. These write English, with a point before the decimals.

PHP
fragments/numbers_2.php
HTML
fragments/numbers_2.pad
Result
<?php

// Counters, a sentence and a download size, for people.

$numbers = [ 950, 1500, 48210, 1534200, 2500000000 ];

$stats = [];

foreach (
$numbers as $number )
$stats [] = [
'number' => $number,
'short' => padNumberAbbreviate ( $number, 1 ),
'words' => padNumberForHumans ( $number, 1 )
];

$download = padNumberFileSize ( 5347737, 1 );

?>
<table border="1" cellpadding="4" cellspacing="0">
<tr><th>number</th><th>abbreviate</th><th>for humans</th></tr>
{stats}
<tr><td>{$number}</td><td>{$short}</td><td>{$words}</td></tr>
{/stats}
</table>
<p>The download is {$download}.</p>
number abbreviate for humans
950 950 950
1500 1.5K 1.5 thousand
48210 48.2K 48.2 thousand
1534200 1.5M 1.5 million
2500000000 2.5B 2.5 billion

The download is 5.1 MB.

Places and bounds

padNumberOrdinal writes the English place of a whole number - 11th, 12th and 13th take th, as do 111th to 113th. padNumberClamp keeps a number between a minimum and a maximum: a page number from the address that has to stay within the pages there are.

PHP
fragments/numbers_3.php
HTML
fragments/numbers_3.pad
Result
<?php

// The page number from the address, kept within the pages
// there are, and the places of a race.

$pages = 12;
$kept = [];

foreach ( [ -
3, 4, 40 ] as $asked )
$kept [] = [
'asked' => $asked,
'shown' => padNumberClamp ( $asked, 1, $pages )
];

$finished = [ 1, 2, 3, 11, 22, 101 ];
$ordinals = array_map ( 'padNumberOrdinal', $finished );
$places = implode ( ', ', $ordinals );

?>
{kept}
<p>Page {$asked} asked, page {$shown} shown</p>
{/kept}
<p>{$places}</p>

Page -3 asked, page 1 shown

Page 4 asked, page 4 shown

Page 40 asked, page 12 shown

1st, 2nd, 3rd, 11th, 22nd, 101st

In a template

The abbreviate pipe is padNumberAbbreviate - {$views | abbreviate}, {$views | abbreviate(1)} - and the ordinal pipe is padNumberOrdinal. A value that is not a number goes through them unchanged, as it does through bytes.

PHP
fragments/numbers_4.php
HTML
fragments/numbers_4.pad
Result
<?php

// The PHP hands over plain numbers; the template writes them
// for people.

$runners = [
[
'name' => 'Ann', 'place' => 1, 'views' => 1534200 ],
[
'name' => 'Bob', 'place' => 2, 'views' => 48210 ],
[
'name' => 'Cee', 'place' => 3, 'views' => 950 ]
];

?>
{runners}
<p>{$place | ordinal}: {$name},
{$views | abbreviate(1)} views</p>
{/runners}

1st: Ann, 1.5M views

2nd: Bob, 48.2K views

3rd: Cee, 950 views

Nothing and mistakes

NULL, FALSE and empty text are nothing to write: every function answers an empty string for them, padNumberClamp NULL. A value that is no number, a negative precision, a fraction handed to padNumberOrdinal, a locale intl does not know and a minimum above the maximum are reported as errors that name the function.