Инструменты для работы с числовыми форматами в PHP
Основные методы форматирования чисел
В PHP существует несколько способов привести число к нужному строковому представлению. Выбор зависит от задачи: разделители тысяч, количество десятичных знаков, локаль.
Как отформатировать число с разделителями тысяч и фиксированным числом знаков после запятой?
Наиболее эффективное решение - функция number_format. Она принимает число, количество десятичных знаков, десятичный разделитель и разделитель тысяч.
<?php
$number = 1234567.891;
echo number_format($number, 2, '.', ',');
// Результат: 1,234,567.89
?>1,234,567.89
Проблема: при передаче очень больших чисел (превышающих размер int/float) number_format может привести к потере точности, так как сначала преобразует в float. Решение: использовать строки и BCMath, либо передавать число как строку, если оно в пределах точности float.
Как задать количество знаков после запятой без разделителей тысяч?
Если нужно только округление до N знаков, можно использовать sprintf с форматом '%.Nf'.
<?php
echo sprintf('%.2f', 123.456);
// 123.46
?>123.46
Проблема: sprintf использует десятичный разделитель, установленный в локали (setlocale). Если локаль не задана, он может использовать точку, но на некоторых серверах может быть запятая. Для явного задания разделителя лучше использовать number_format.
Как округлить число вниз или вверх до целого или до заданного количества знаков?
Функции floor и ceil округляют дробное число вниз и вверх соответственно. Для округления до определённого количества знаков можно комбинировать с умножением.
<?php
$number = 123.456;
echo floor($number * 100) / 100; // 123.45
echo ceil($number * 100) / 100; // 123.46
?>123.45 123.46
Проблема: из-за неточности float операции вида floor/ceil могут дать неверный результат для чисел, которые не точно представимы (например, 0.1). Рекомендуется использовать BCMath для критичных расчётов.
Как отформатировать число в денежном формате с учётом локали?
Класс NumberFormatter из расширения intl предоставляет локализованное форматирование валют, процентов, десятичных чисел.
<?php
$fmt = new NumberFormatter('ru_RU', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(1234567.89, 'RUB');
?>1 234 567,89 руб.
Проблема: требуется установленное расширение intl. Без него класс недоступен. Также поведение может различаться в разных версиях ICU.
Каждый из рассмотренных подходов подходит для определённого круга задач. Основным рабочим инструментом остаётся number_format, но для локализации и точных операций стоит обращаться к NumberFormatter и BCMath.
Расширенные примеры и нестандартные сценарии
Ниже приведены примеры, демонстрирующие более сложные или редкие случаи форматирования чисел в PHP.
Пример 1: Форматирование отрицательного числа с сохранением знака
<?php
$number = -1234567.891;
echo number_format($number, 2, '.', ',');
// Результат: -1,234,567.89
?>-1,234,567.89
Функция number_format корректно обрабатывает отрицательные числа, помещая знак минус перед числом.
Пример 2: Замена разделителя тысяч через str_replace после number_format
<?php
$formatted = number_format(1234567.89, 2, '.', ',');
echo str_replace(',', ' ', $formatted);
// Результат: 1 234 567.89
?>1 234 567.89
Иногда требуется нестандартный разделитель тысяч. Можно преобразовать строку после форматирования.
Пример 3: Использование BCMath для точного округления до 2 знаков
<?php
$number = '1234567.895';
echo bcadd($number, '0', 2);
// Результат: 1234567.89 (отбрасывание)
echo round($number, 2);
// Может дать 1234567.90 из-за float
?>1234567.89 1234567.90
При работе с денежными суммами лучше использовать BCMath, так как round на float может дать неожиданный результат из-за двоичного представления.
Пример 4: Форматирование процентов с NumberFormatter
<?php
$fmt = new NumberFormatter('en_US', NumberFormatter::PERCENT);
echo $fmt->format(0.125);
// Результат: 12%
?>12%
NumberFormatter автоматически умножает число на 100 и добавляет знак процента. Локализация влияет на положение знака.
Пример 5: Форматирование с фиксированной длиной целой части (ведущие нули)
<?php
$number = 42;
echo str_pad($number, 5, '0', STR_PAD_LEFT);
// Результат: 00042
?>00042
Если требуется, чтобы число имело определённое количество цифр, str_pad добавляет нули слева. Можно комбинировать с number_format для десятичной части.
Пример 6: Обработка бесконечности и NaN
<?php
$inf = INF;
echo number_format($inf, 2);
// Результат: INF (строка)
$nan = NAN;
echo number_format($nan, 2);
// Результат: NAN
?>INF NAN
Специальные значения float не форматируются как числа, а просто преобразуются в строку 'INF' или 'NAN'. Перед форматированием стоит проверять через is_finite.
Пример 7: Разделение числа на целую и дробную части с округлением
<?php
$number = 123.4567;
$intPart = floor($number);
$fracPart = round($number - $intPart, 2);
echo sprintf('%d.%02d', $intPart, abs($fracPart) * 100);
// Результат: 123.46
?>123.46
Такой ручной подход даёт полный контроль над форматированием, но требует внимания к отрицательным числам и точности.
Эти примеры охватывают типичные и нестандартные задачи форматирования чисел в PHP. Выбор конкретного способа зависит от требуемой точности, локализации и структуры выходных данных.