NumberFormatter no PHP: R$ formatado e valor por extenso em pt-BR

O number_format($v, 2, ',', '.') resolve os separadores e para por aí: ele não sabe pôr o R$ na frente nem escrever “mil duzentos e trinta e quatro reais” no rodapé do boleto. Quem faz isso é a classe NumberFormatter, que vem com a extensão intl e já entende pt-BR sem você escrever um único array de dezenas.

Moeda e extenso em cinco linhas

$moeda = new NumberFormatter('pt_BR', NumberFormatter::CURRENCY);
echo $moeda->formatCurrency(1234.5, 'BRL');  // R$ 1.234,50

$extenso = new NumberFormatter('pt_BR', NumberFormatter::SPELLOUT);
echo $extenso->format(1234);  // mil duzentos e trinta e quatro

Para o valor cheio, separe reais e centavos antes. Jogar 1234.50 direto no SPELLOUT devolve mil duzentos e trinta e quatro vírgula cinco, que não serve para nota nem para boleto:

$valor = 1234.50;
$centavos = (int) round(fmod($valor, 1) * 100);
$texto = $extenso->format((int) $valor) . ' reais';
if ($centavos > 0) {
    $texto .= ' e ' . $extenso->format($centavos) . ' centavos';
}
echo $texto;  // mil duzentos e trinta e quatro reais e cinquenta centavos

Dois tropeços que custam tempo

O primeiro é o erro Uncaught Error: Class "NumberFormatter" not found. Falta a extensão: sudo apt install php8.3-intl e depois sudo systemctl restart php8.3-fpm. Confirme com php -m | grep intl, e lembre que o CLI e o FPM podem carregar php.ini diferentes — funcionar no terminal não quer dizer funcionar no site.

O segundo é mais silencioso: o espaço entre o R$ e o número é um espaço não separável (U+00A0), não o espaço da barra. Se você compara a string com 'R$ 1.234,50' num teste, ou tenta um str_replace('R$ ', '', $s), nunca bate. Para voltar ao float use $moeda->parseCurrency($s, $cur), que devolve o número e ainda preenche $cur com BRL, em vez de mexer no texto na unha.

Dúvidas? Faça um comentário logo abaixo ou envie uma mensagem clicando aqui.

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *