Convertir número a letras en PHP 8 (español)

Función PHP 8 que convierte cualquier número entero entre -999.999.999 y 999.999.999 en su representación literal en español. Maneja correctamente los casos especiales del español: "veintiún", "cien" vs "ciento", "un millón" vs "dos millones", negativos y ceros. Incluye un ejemplo de uso práctico para escribir importes en facturas o cheques con el formato "SON: DOS MIL TRESCIENTOS CINCUENTA Y UN EUROS CON SETENTA Y CINCO CÉNTIMOS".
				<?php
/**
* Convierte un número entero en su representación literal en español
*
* Soporta números del 0 al 999.999.999 (casi mil millones).
* Útil para facturas, cheques, documentos legales y contratos donde
* hay que escribir el importe con letras.
*
* Ejemplos:
* numero_a_literal(0) ? 'cero'
* numero_a_literal(21) ? 'veintiún'
* numero_a_literal(100) ? 'cien'
* numero_a_literal(101) ? 'ciento uno'
* numero_a_literal(23456) ? 'veintitrés mil cuatrocientos cincuenta y seis'
* numero_a_literal(1000000) ? 'un millón'
*
* Código mejorado por David Carrero — https://carrero.es
* Fecha de modificación: 2026-05-09
*/

function numero_a_literal(int $n): string
{
if ($n < 0) {
return 'menos ' . numero_a_literal(abs($n));
}

$unidades = ['', 'uno', 'dos', 'tres', 'cuatro', 'cinco',
'seis', 'siete', 'ocho', 'nueve', 'diez',
'once', 'doce', 'trece', 'catorce', 'quince',
'dieciséis', 'diecisiete', 'dieciocho', 'diecinueve'];

$decenas = ['', 'diez', 'veinte', 'treinta', 'cuarenta', 'cincuenta',
'sesenta', 'setenta', 'ochenta', 'noventa'];

$centenas = ['', 'ciento', 'doscientos', 'trescientos', 'cuatrocientos',
'quinientos', 'seiscientos', 'setecientos', 'ochocientos', 'novecientos'];

if ($n === 0) return 'cero';
if ($n === 100) return 'cien';
if ($n === 21) return 'veintiún';

if ($n < 20) {
return $unidades[$n];
}

if ($n < 30) {
return $n === 20 ? 'veinte' : 'veinti' . $unidades[$n - 20];
}

if ($n < 100) {
$dec = intdiv($n, 10);
$rest = $n % 10;
return $rest === 0
? $decenas[$dec]
: $decenas[$dec] . ' y ' . $unidades[$rest];
}

if ($n < 1_000) {
$cen = intdiv($n, 100);
$rest = $n % 100;
if ($rest === 0) return $centenas[$cen];
$sep = $cen === 1 ? 'ciento ' : $centenas[$cen] . ' ';
return $sep . numero_a_literal($rest);
}

if ($n < 1_000_000) {
$miles = intdiv($n, 1_000);
$rest = $n % 1_000;
$prefijo = $miles === 1 ? 'mil' : numero_a_literal($miles) . ' mil';
return $rest === 0
? $prefijo
: $prefijo . ' ' . numero_a_literal($rest);
}

if ($n < 1_000_000_000) {
$millones = intdiv($n, 1_000_000);
$rest = $n % 1_000_000;
$prefijo = $millones === 1
? 'un millón'
: numero_a_literal($millones) . ' millones';
return $rest === 0
? $prefijo
: $prefijo . ' ' . numero_a_literal($rest);
}

return 'número demasiado grande';
}

// ?? Demo ??????????????????????????????????????????????????????????????????????

$ejemplos = [
0, 1, 10, 15, 20, 21, 30, 99, 100, 101, 200, 500,
999, 1000, 1001, 1100, 10000, 21000, 23456,
100000, 500000, 999999, 1000000, 5000000, 123456789
];

echo "Número a literal en españoln";
echo str_repeat('?', 55) . "n";
foreach ($ejemplos as $num) {
echo str_pad((string)$num, 12) . ' ? ' . numero_a_literal($num) . "n";
}

// ?? Uso práctico: importe en factura ?????????????????????????????????????????
echo "nEjemplo factura:n";
$importe = 2351.75;
$enteros = (int)$importe;
$centimos = round(($importe - $enteros) * 100);
echo "Son: " . strtoupper(numero_a_literal($enteros)) . " EUROS";
if ($centimos > 0) {
echo " CON " . numero_a_literal((int)$centimos) . " CÉNTIMOS";
}
echo ".n";
Descargar adjuntos
COMPARTE ESTE TUTORIAL

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
SIGUIENTE TUTORIAL