Desafio PHP

Função variádica com argumentos nomeados e valor padrão

Enunciado

Crie uma função relatorio que recebe um título (string), uma lista variádica de números e um separador (string, padrão ', '). A função deve retornar uma string com o título, dois pontos, espaço e os números separados pelo separador. Os números devem ser formatados com duas casas decimais. Use argumentos nomeados para passar o separador e a lista de números.

Requisitos

  • A função deve se chamar relatorio e ter parâmetros: $titulo (string), ...$numeros (variádico de float) e $separador (string, padrão ', ').
  • Deve retornar uma string no formato "Título: 1.00, 2.50, 3.75".
  • Na chamada, use argumentos nomeados para passar separador e numeros (como array) usando o operador de desempacotamento ....
  • Se nenhum número for passado, deve retornar apenas "Título: " (título, dois pontos e espaço).

Código inicial

<?php
// Complete a função relatorio
function relatorio(string $titulo, float ...$numeros): string {
    // seu código aqui
}

// Testes
echo relatorio('Vendas', 10.5, 20.75, 30.0) . PHP_EOL;
echo relatorio(titulo: 'Compras', numeros: [1.5, 2.5], separador: ' | ') . PHP_EOL;
echo relatorio('Sem números') . PHP_EOL;

Saída esperada

Vendas: 10.50, 20.75, 30.00
Compras: 1.50 | 2.50
Sem números:
Ver dica

Use array_map para formatar cada número com number_format. Para o caso vazio, implode em um array vazio retorna string vazia.

Mostrar solução
<?php
declare(strict_types=1);

function relatorio(string $titulo, float ...$numeros): string {
    // Formata cada número com duas casas decimais
    $formatados = array_map(fn($n) => number_format($n, 2, '.', ''), $numeros);
    $lista = implode($separador ?? ', ', $formatados);
    return "$titulo: $lista";
}

// Para suportar separador nomeado, precisamos ajustar a assinatura:
// Não é possível ter parâmetro variádico antes de um parâmetro normal.
// Então usamos uma abordagem alternativa: passar separador como argumento nomeado
// não funciona diretamente com variádico. Vamos modificar a função para aceitar
// um array associativo ou usar um parâmetro opcional antes do variádico.

// Solução correta: colocar $separador antes do variádico, mas aí ele não pode ser
// passado por nome se o variádico vier depois. A melhor forma é usar um array
// para os números e um parâmetro separado.

// Vamos reescrever a função para atender ao enunciado:
function relatorio(string $titulo, string $separador = ', ', float ...$numeros): string {
    $formatados = array_map(fn($n) => number_format($n, 2, '.', ''), $numeros);
    return "$titulo: " . implode($separador, $formatados);
}

// Agora as chamadas com argumentos nomeados funcionam:
echo relatorio('Vendas', 10.5, 20.75, 30.0) . PHP_EOL;
echo relatorio(titulo: 'Compras', separador: ' | ', numeros: [1.5, 2.5]) . PHP_EOL;
echo relatorio('Sem números') . PHP_EOL;

Passo a passo

  1. A função relatorio recebe $titulo, $separador (padrão ', ') e uma lista variádica ...$numeros.
  2. Usamos array_map com uma arrow function para formatar cada número com number_format($n, 2, '.', '').
  3. implode($separador, $formatados) junta os números formatados usando o separador.
  4. Retornamos a string interpolada com título, dois pontos, espaço e a lista.
  5. Na primeira chamada, passamos os números posicionalmente; o separador usa o padrão.
  6. Na segunda chamada, usamos argumentos nomeados: titulo, separador e numeros (com desempacotamento de array).
  7. Na terceira chamada, nenhum número é passado, então $numeros é um array vazio e implode retorna string vazia, resultando em "Sem números: ".

Por que funciona

A função variádica coleta todos os argumentos extras em $numeros. Ao colocar $separador antes do variádico, podemos passá-lo por nome e ainda usar o desempacotamento para o array de números. O array_map aplica a formatação a cada elemento, e implode monta a string final. O valor padrão de $separador é usado quando não fornecido.

Erros comuns

  • Colocar o parâmetro variádico antes de um parâmetro normal: function relatorio(string $titulo, float ...$numeros, string $separador = ', ') é erro de sintaxe, pois o variádico deve ser o último. Solução: inverter a ordem, colocando $separador antes de ...$numeros.
  • Tentar passar separador como argumento nomeado quando ele vem depois do variádico: não é possível, pois o variádico captura todos os argumentos restantes. Solução: reordenar os parâmetros.
  • Esquecer o declare(strict_types=1): pode causar conversões indesejadas. Solução: incluir no topo.

Outra forma de resolver

Usar um array em vez de variádico:

function relatorio(string $titulo, array $numeros, string $separador = ', '): string {
    $formatados = array_map(fn($n) => number_format($n, 2, '.', ''), $numeros);
    return "$titulo: " . implode($separador, $formatados);
}
echo relatorio('Vendas', [10.5, 20.75, 30.0]);

Prefira variádico quando a lista é naturalmente uma lista de argumentos; use array quando a lista já é um array.

Saída esperada

Vendas: 10.50, 20.75, 30.00
Compras: 1.50 | 2.50
Sem números: