number_format en PHP: mostrar números y precios formateados

number_format() convierte un número en una cadena con el formato de separadores que espera el usuario: punto de miles y coma decimal en español, coma de miles y punto decimal en inglés. Es la función estándar para mostrar precios, cantidades y porcentajes en PHP, aunque hay detalles que conviene conocer antes de confiar ciegamente en el resultado.

Los cuatro parámetros

<?php
number_format(
    float  $num,
    int    $decimals         = 0,
    string $decimal_separator  = '.',
    string $thousands_separator = ','
): string
?>

Si solo pasas el número, devuelve un entero sin decimales y con comas como separador de miles (formato anglosajón). Para euros en español necesitas los cuatro argumentos:

<?php
$precio = 12890.5;

echo number_format($precio);                       // 12,891 (redondea, sin decimales)
echo number_format($precio, 2);                    // 12,890.50 (anglosajón)
echo number_format($precio, 2, ',', '.');          // 12.890,50 (español/Europa)
echo number_format($precio, 2, ',', '') . ' €';   // 12890,50 € (sin separador de miles)
?>

Formatear precios en euros

<?php
function precio(float $importe, string $moneda = '€'): string
{
    return number_format($importe, 2, ',', '.') . ' ' . $moneda;
}

$productos = [
    ['nombre' => 'Camiseta',    'precio' => 19.9],
    ['nombre' => 'Pantalón',    'precio' => 39.95],
    ['nombre' => 'Zapatillas', 'precio' => 129.99],
    ['nombre' => 'Abrigo',     'precio' => 2499.0],
];

foreach ($productos as $p) {
    echo str_pad($p['nombre'], 15) . precio($p['precio']) . "n";
}
// Camiseta        19,90 €
// Pantalón        39,95 €
// Zapatillas      129,99 €
// Abrigo          2.499,00 €
?>

Combinar con sprintf()

Cuando necesitas mostrar el precio dentro de una cadena más larga, combinar number_format() con sprintf() mantiene el código limpio:

<?php
$base  = 450.0;
$iva   = 21;
$total = $base * (1 + $iva / 100);

$linea = sprintf(
    'Base imponible: %s | IVA (%d%%): %s | Total: %s',
    number_format($base,  2, ',', '.'),
    $iva,
    number_format($total - $base, 2, ',', '.'),
    number_format($total, 2, ',', '.')
);

echo $linea;
// Base imponible: 450,00 | IVA (21%): 94,50 | Total: 544,50
?>

Diferencia con money_format() (eliminada en PHP 8)

money_format() existía en PHP para formatear cantidades según la configuración regional del sistema (locale). Se marcó como obsoleta en PHP 7.4 y se eliminó en PHP 8.0. Si ves código legacy que la usa, sustitúyela por number_format() con los separadores correctos, o por la clase NumberFormatter de la extensión intl si necesitas soporte completo de locales:

<?php
// PHP 8+: usar NumberFormatter (extensión intl)
$fmt = new NumberFormatter('es_ES', NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(12890.5, 'EUR');
// 12.890,50 €
?>

Por qué number_format() no resuelve la precisión de los floats

number_format() redondea al número de decimales indicado, pero el número interno sigue siendo un float con los problemas de representación binaria de siempre. Para cálculos financieros precisos usa bcmath o trabaja en céntimos (enteros):

<?php
$a = 0.1 + 0.2;
echo $a;                              // 0.3 (pero no exactamente)
echo number_format($a, 2, ',', '.'); // 0,30 (parece correcto)
echo ($a == 0.3 ? 'igual' : 'distinto'); // distinto

// Con bcmath
$suma = bcadd('0.1', '0.2', 10);
echo $suma; // 0.3000000000
?>

La documentación oficial de number_format() incluye ejemplos de comportamiento con distintos locales y las notas sobre la precisión de los tipos flotantes.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP