PHP

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.

Post Recentes

Erro 500 no Magento 2: achar o relatório em var/report pelo ID da tela

O hash que o Magento mostra junto do erro é o nome de um arquivo em var/report. Veja como abrir,…

24 horas atrás

Campo extra no checkout em blocos do WooCommerce sem voltar pro shortcode

Seu snippet com woocommerce_checkout_fields parou de aparecer no checkout em blocos. Registre o campo pela API nova e leia o…

2 dias atrás

Fuso horário no PHP 8.3: log com 3 horas de diferença no servidor

O pedido entrou às 21h e o relatório mostra 00h do dia seguinte. Onde setar date.timezone no PHP 8.3 e…

3 dias atrás

Magento 2 não envia e-mail de pedido: async sending e cron parado

O pedido entra na loja e o e-mail nunca sai: antes de culpar o SMTP, veja o envio assíncrono, a…

3 dias atrás

cron_schedules WordPress: intervalo de 5 minutos no WP-Cron

O WordPress só oferece hourly, twicedaily, daily e weekly. Use o filtro cron_schedules para criar um intervalo de 5 minutos…

4 dias atrás

E-mails do WooCommerce não chegam: como testar o envio de um pedido real

Dispare pela linha de comando o e-mail de um pedido que já existe na loja e descubra se a falha…

4 dias atrás