Named arguments: chamando funções com clareza
1. O que são Named Arguments e por que surgiram?
Antes do PHP 8.0, chamar funções com múltiplos parâmetros opcionais era um pesadelo. Você precisava lembrar a ordem exata dos parâmetros e frequentemente passava null para parâmetros intermediários que não queria modificar. Isso gerava código confuso e propenso a erros.
// A velha forma: ordem importa, muitos nulls
function configurarSistema($host, $porta = 3306, $usuario = 'root', $senha = '', $ssl = false, $timeout = 30) {
// ...
}
// Chamada confusa: o que é true? SSL? Debug? Cache?
configurarSistema('localhost', 3306, 'admin', '123', true, 60);
Named arguments, introduzidos no PHP 8.0 através da RFC "Named Arguments", resolveram esse problema permitindo que você especifique o nome do parâmetro na chamada da função.
// Nova forma: clara e auto-documentada
configurarSistema(
host: 'localhost',
usuario: 'admin',
ssl: true,
timeout: 60
);
2. Sintaxe e regras fundamentais
A sintaxe é simples: use nomeDoParametro: valor separado por vírgulas.
function criarUsuario($nome, $email, $ativo = true, $tipo = 'comum', $notificar = false) {
// lógica...
}
// Ordem arbitrária - funciona!
criarUsuario(
email: 'joao@email.com',
nome: 'João Silva',
tipo: 'admin',
notificar: true
);
Regras importantes:
- Argumentos posicionais devem vir antes dos nomeados
- Não é possível misturar no mesmo parâmetro (ex: $nome: 'João' posicional não funciona)
- O nome deve corresponder exatamente ao parâmetro da função
// Válido: posicionais primeiro, depois nomeados
criarUsuario('Maria', 'maria@email.com', tipo: 'moderador');
// Inválido: nomeado antes de posicional
criarUsuario(email: 'maria@email.com', 'Maria'); // Erro!
3. Vantagens práticas na legibilidade do código
O maior benefício é eliminar parâmetros "mágicos" que exigem consulta à documentação:
// Antes - o que significa cada booleano?
$query->where('status', '=', 'ativo')
->orderBy('nome', 'asc')
->limit(10, 20);
// Depois - auto-documentado
$query->where(
coluna: 'status',
operador: '=',
valor: 'ativo'
)->orderBy(
coluna: 'nome',
direcao: 'asc'
)->limit(
offset: 10,
quantidade: 20
);
Para funções com parâmetros do mesmo tipo, os named arguments evitam trocas acidentais:
function calcularDistancia($x1, $y1, $x2, $y2) {
return sqrt(($x2 - $x1)**2 + ($y2 - $y1)**2);
}
// Antes: fácil trocar x2 com y1
calcularDistancia(0, 0, 3, 4);
// Depois: impossível errar
calcularDistancia(x1: 0, y1: 0, x2: 3, y2: 4);
4. Trabalhando com parâmetros opcionais e valores padrão
A capacidade de pular parâmetros intermediários é revolucionária:
function criarConexao(
$driver = 'mysql',
$host = 'localhost',
$porta = 3306,
$banco = 'test',
$usuario = 'root',
$senha = '',
$charset = 'utf8mb4',
$collation = 'utf8mb4_unicode_ci'
) {
// ...
}
// Antes: precisava passar null para tudo
criarConexao('mysql', 'localhost', 3306, 'meubanco', 'admin', null, null, null);
// Depois: especifique apenas o necessário
criarConexao(
banco: 'meubanco',
usuario: 'admin',
charset: 'utf8'
);
Comparado com a abordagem antiga de arrays associativos:
// Abordagem antiga com array
criarConexaoArray([
'banco' => 'meubanco',
'usuario' => 'admin'
]);
// Named arguments é mais elegante e com type hinting preservado
criarConexao(banco: 'meubanco', usuario: 'admin');
5. Named arguments com variadic functions e spread operator
Com funções variádicas, os named arguments têm limitações importantes:
function somar(...$numeros) {
return array_sum($numeros);
}
// Isso funciona - spread operator
$args = [1, 2, 3];
somar(...$args);
// Isso NÃO funciona - named argument não pode ser capturado por variadic
somar(numeros: [1, 2, 3]); // Erro! 'numeros' não é um parâmetro nomeável
Exemplo prático com compact():
function registrarLog($mensagem, $nivel = 'info', $contexto = []) {
// ...
}
$usuario = 'João';
$acao = 'login';
$ip = '192.168.1.1';
// Spread com named arguments
registrarLog(
mensagem: 'Usuário realizou ação',
contexto: compact('usuario', 'acao', 'ip')
);
6. Limitações e cuidados importantes
Callbacks dinâmicos: Named arguments não funcionam com call_user_func_array() de forma direta:
function processar($nome, $idade) {
echo "$nome tem $idade anos";
}
// Isso funciona
call_user_func_array('processar', ['João', 30]);
// Isso NÃO funciona
call_user_func_array('processar', ['nome' => 'João', 'idade' => 30]); // Erro!
Funções internas: Muitas funções built-in do PHP não suportam named arguments porque seus parâmetros não têm nomes definidos:
// Isso funciona
array_map('strtoupper', ['a', 'b']);
// Isso NÃO funciona
array_map(callback: 'strtoupper', array: ['a', 'b']); // Erro!
Performance: Em loops intensivos, o overhead de named arguments é mínimo (~5-10%), mas pode ser relevante:
// Em loops críticos, prefira posicional
for ($i = 0; $i < 1000000; $i++) {
funcaoPesada(valor: $i, opcao: true); // Mais lento
funcaoPesada($i, true); // Mais rápido
}
7. Casos de uso reais e boas práticas
Laravel Query Builder:
User::query()
->where(column: 'status', operator: '=', value: 'ativo')
->orderBy(column: 'criado_em', direction: 'desc')
->take(value: 10)
->get();
Symfony Forms:
$form->add(
name: 'email',
type: EmailType::class,
options: [
'required' => true,
'label' => 'E-mail'
]
);
Testes unitários com PHPUnit:
$mock = $this->createMock(UsuarioRepository::class);
$mock->method('find')
->with(id: 42, includeDeleted: false)
->willReturn($usuario);
Quando usar:
- Funções com 4+ parâmetros
- Parâmetros booleanos (evite true/false soltos)
- Parâmetros opcionais no meio da lista
- APIs públicas de bibliotecas
Quando evitar:
- Funções com 2-3 parâmetros óbvios (somar($a, $b))
- Loops extremamente críticos de performance
- Callbacks dinâmicos com call_user_func()
8. Exemplo completo: refatorando uma função complexa
Vamos refatorar uma função típica de criação de usuário:
// Versão original - péssima legibilidade
function criarUsuario(
$nome,
$email,
$ativo = true,
$verificado = false,
$tipo = 'comum',
$plano = null,
$notificar = true,
$roles = ['usuario']
) {
// lógica complexa...
}
// Chamada original - o que cada parâmetro significa?
criarUsuario(
'João Silva',
'joao@email.com',
true, // ativo?
false, // verificado?
'admin', // tipo
null, // plano?
true // notificar?
);
Refatoração com named arguments:
// Agora a chamada é auto-documentada
criarUsuario(
nome: 'João Silva',
email: 'joao@email.com',
tipo: 'admin',
notificar: true,
roles: ['admin', 'editor']
);
// Manutenção facilitada - adicionar/remover parâmetros não quebra chamadas
criarUsuario(
nome: 'Maria Santos',
email: 'maria@email.com',
tipo: 'moderador',
// Note: não preciso especificar ativo, verificado, plano
);
Benefícios no longo prazo:
1. Menos bugs: Trocar parâmetros de posição é impossível
2. Documentação viva: O código se explica
3. Refatoração segura: Adicionar novos parâmetros opcionais não quebra nada
4. Produtividade: IDE mostra os nomes dos parâmetros, facilitando chamadas complexas
Named arguments transformaram a forma como escrevemos PHP, especialmente em APIs públicas e funções de configuração. Use-os com sabedoria e seu código será mais claro, seguro e fácil de manter.
Referências
- PHP Manual: Named Arguments — Documentação oficial do PHP sobre a sintaxe e regras de named arguments
- PHP 8.0: Named Arguments RFC — Proposta original que introduziu named arguments no PHP 8.0, com discussões técnicas e exemplos
- Stitcher.io: Named arguments in PHP 8 — Artigo técnico detalhado com exemplos práticos e casos de uso avançados
- PHP.Watch: PHP 8.0 Named Arguments — Guia completo com exemplos interativos e comparações com versões anteriores
- Laravel News: Named Arguments in Laravel — Como usar named arguments em projetos Laravel, incluindo Query Builder e Eloquent
- Symfony Blog: PHP 8 Features for Symfony Developers — Guia oficial do Symfony sobre como aproveitar named arguments em formulários e componentes