Nesta aula, vamos explorar recursos avançados de funções em PHP que permitem maior flexibilidade e expressividade. Começaremos com parâmetros variádicos, que possibilitam receber um número variável de argumentos, e depois veremos argumentos nomeados, introduzidos no PHP 8, que melhoram a legibilidade ao passar argumentos. O operador spread será abordado como forma de expandir arrays em argumentos de função. Por fim, discutiremos o type juggling em parâmetros, entendendo como o PHP converte tipos automaticamente e como podemos controlar isso.

Parâmetros variádicos (...)

Parâmetros variádicos permitem que uma função aceite um número indefinido de argumentos. Eles são declarados com três pontos (...) antes do nome do parâmetro, que se torna um array contendo todos os argumentos passados. Isso é útil quando você não sabe quantos argumentos serão fornecidos, como em funções de soma ou logging.

Exemplo: uma função que soma todos os números passados.

function soma(...$numeros) {
    return array_sum($numeros);
}

echo soma(1, 2, 3); // 6
echo soma(4, 5, 6, 7); // 22

Importante: o parâmetro variádico deve ser o último na lista de parâmetros. Você pode ter parâmetros normais antes dele.

function saudacao($prefixo, ...$nomes) {
    foreach ($nomes as $nome) {
        echo "$prefixo $nome\n";
    }
}
saudacao("Olá", "João", "Maria", "Pedro");

Argumentos nomeados (PHP 8)

Argumentos nomeados permitem passar argumentos para uma função especificando o nome do parâmetro, em vez de depender da ordem. Isso melhora a legibilidade e permite pular parâmetros opcionais. A sintaxe usa o nome do parâmetro seguido de dois pontos e o valor.

Exemplo:

function criarUsuario($nome, $email, $ativo = true, $admin = false) {
    // ...
}

// Uso tradicional (ordem)
criarUsuario("João", "joao@email.com", true, false);

// Com argumentos nomeados (mais claro)
criarUsuario(
    nome: "João",
    email: "joao@email.com",
    admin: true
);

Note que pulamos o parâmetro $ativo (usa o valor padrão) e especificamos apenas os que queremos. A ordem não importa, mas os nomes devem corresponder aos parâmetros da função.

Spread

O operador spread (...) é usado para expandir um array (ou Traversable) em argumentos individuais ao chamar uma função. Ele é o oposto dos parâmetros variádicos: em vez de coletar argumentos em um array, ele espalha um array em argumentos.

Exemplo:

function soma($a, $b, $c) {
    return $a + $b + $c;
}

$numeros = [1, 2, 3];
echo soma(...$numeros); // 6

Spread também pode ser usado em declarações de array para mesclar arrays:

$arr1 = [1, 2];
$arr2 = [3, 4];
$resultado = [...$arr1, ...$arr2]; // [1, 2, 3, 4]

Type juggling em parâmetros

PHP é uma linguagem de tipagem dinâmica e realiza conversões automáticas de tipos (type juggling) quando necessário. Em parâmetros de função, isso significa que você pode passar um valor de um tipo e o PHP tentará convertê-lo para o tipo esperado, se possível. Por exemplo, se uma função espera uma string e você passa um inteiro, ele será convertido para string.

Exemplo:

function mostraIdade($idade) {
    echo "Idade: $idade anos";
}

mostraIdade(25); // Funciona, 25 é convertido para string
mostraIdade("25"); // Também funciona

No entanto, isso pode levar a comportamentos inesperados. Para evitar problemas, você pode usar declarações de tipo (type hints) desde o PHP 5, e desde o PHP 7, você pode usar tipos escalares com modo estrito (strict_types). Com strict_types=1, o PHP lançará um erro se o tipo não corresponder exatamente (sem conversão automática).

Exemplo com strict_types:

declare(strict_types=1);

function soma(int $a, int $b): int {
    return $a + $b;
}

echo soma(1, 2); // 3
echo soma("1", 2); // Erro: Argument 1 must be of type int, string given

Sem strict_types, o PHP converteria a string "1" para inteiro 1. O type juggling é útil, mas pode ocultar bugs. Portanto, é recomendável usar declarações de tipo e, em projetos críticos, ativar o modo estrito.

Boas práticas

Ao usar parâmetros variádicos, lembre-se de que eles coletam todos os argumentos extras, então evite misturar com parâmetros opcionais depois. Use argumentos nomeados para melhorar a legibilidade em funções com muitos parâmetros opcionais. O operador spread é ótimo para trabalhar com arrays e funções que esperam argumentos individuais. Quanto ao type juggling, prefira sempre declarar tipos e, se possível, use strict_types para evitar conversões inesperadas.

Referências

Exercícios

  1. Crie uma função chamada concatena que aceite um número variável de strings e as concatene com espaço. Use parâmetros variádicos.

    ✓ Resposta:
    function concatena(...$palavras) {
        return implode(' ', $palavras);
    }
    echo concatena("Olá", "mundo", "PHP"); // "Olá mundo PHP"
    
  2. Escreva uma função configurar que aceite argumentos nomeados para $host, $porta (padrão 3306) e $dbname. Use argumentos nomeados para chamá-la passando apenas host e dbname.

    ✓ Resposta:
    function configurar($host, $porta = 3306, $dbname = '') {
        echo "Host: $host, Porta: $porta, DB: $dbname";
    }
    configurar(host: 'localhost', dbname: 'teste');
    
  3. Dado um array $valores = [10, 20, 30], use o operador spread para passá-los como argumentos para a função array_sum (que espera um array, mas queremos simular uma função que soma três números). Crie uma função somaTres que recebe três números e os soma, e chame-a com spread.

    ✓ Resposta:
    function somaTres($a, $b, $c) {
        return $a + $b + $c;
    }
    $valores = [10, 20, 30];
    echo somaTres(...$valores); // 60
    
  4. Explique o que acontece se você chamar uma função que espera um inteiro, mas passa uma string sem strict_types. Dê um exemplo.

    ✓ Resposta:

    Sem strict_types, o PHP converte automaticamente a string para inteiro se possível. Exemplo:

    function dobra(int $x) {
        return $x * 2;
    }
    echo dobra("5"); // 10 (string "5" convertida para int 5)
    

    Se a string não for numérica, o PHP converte para 0 (com warning).

  5. Crie uma função media que aceita um número variável de argumentos numéricos e retorna a média. Use parâmetros variádicos e type hint para float.

    ✓ Resposta:
    function media(float ...$numeros): float {
        if (count($numeros) === 0) return 0;
        return array_sum($numeros) / count($numeros);
    }
    echo media(10, 20, 30); // 20