Tipos em parâmetros e retorno de funções
1. Introdução à Tipagem em Funções no PHP
A tipagem em parâmetros e retornos de funções no PHP evoluiu de um recurso opcional para uma prática essencial no desenvolvimento profissional. Quando você declara explicitamente os tipos que uma função aceita e retorna, está criando contratos claros que previnem erros em tempo de execução, melhoram a legibilidade do código e servem como documentação viva.
O histórico dessa evolução é marcante: no PHP 5, a tipagem era limitada a objetos, arrays e interfaces. O PHP 7 revolucionou ao introduzir tipos escalares (int, float, string, bool) e tipos de retorno. O PHP 8 elevou o nível com tipos union, intersection, mixed e never, além do atributo #[ReturnTypeWillChange] para retrocompatibilidade.
Os benefícios práticos incluem: captura precoce de bugs, IDEs com autocomplete mais preciso, redução de testes de validação manual e código que se auto-documenta. Uma função com assinatura function calcularTotal(array $itens): float já comunica sua intenção sem precisar ler o corpo.
2. Tipos de Parâmetros: Sintaxe e Exemplos
O PHP suporta uma variedade de tipos para parâmetros:
// Tipos escalares
function processarIdade(int $idade): void {
echo "Idade: $idade";
}
function calcularMedia(float $nota1, float $nota2): float {
return ($nota1 + $nota2) / 2;
}
function saudacao(string $nome): string {
return "Olá, $nome!";
}
function isAtivo(bool $status): bool {
return $status;
}
// Tipos compostos
function somarNumeros(array $numeros): int {
return array_sum($numeros);
}
function executarCallback(callable $callback, $valor) {
return $callback($valor);
}
// Tipos especiais
function logMisto(mixed $dado): void {
var_dump($dado);
}
// Exemplo completo com chamada
function criarUsuario(string $nome, string $email, int $idade): array {
return [
'nome' => $nome,
'email' => $email,
'idade' => $idade,
'criado_em' => date('Y-m-d H:i:s')
];
}
$usuario = criarUsuario('Maria', 'maria@email.com', 28);
// TypeError se passar tipos incorretos
3. Tipos de Retorno: Garantindo o Valor de Saída
A declaração de tipo de retorno usa a sintaxe : tipo após os parênteses dos parâmetros:
// Retorno void - função que não retorna valor
function logErro(string $mensagem): void {
file_put_contents('erros.log', $mensagem . PHP_EOL, FILE_APPEND);
}
// Retorno never - função que nunca retorna (lança exceção ou loop infinito)
function abortar(string $mensagem): never {
throw new \RuntimeException($mensagem);
}
function loopInfinito(): never {
while (true) {
// processamento contínuo
}
}
// Retorno tipado com objeto
class Pessoa {
public function __construct(
public string $nome,
public int $idade
) {}
}
function criarPessoa(string $nome, int $idade): Pessoa {
return new Pessoa($nome, $idade);
}
// Exemplo prático com validação
function dividir(int $a, int $b): float|false {
if ($b === 0) {
return false;
}
return $a / $b;
}
$resultado = dividir(10, 3); // 3.333...
$erro = dividir(10, 0); // false
4. Tipos Nullable e Valores Padrão
Tipos nullable permitem que um parâmetro ou retorno aceite null além do tipo especificado:
// Parâmetros nullable com valor padrão
function buscarUsuario(?int $id = null): ?array {
if ($id === null) {
return null; // ou buscar todos
}
// lógica para buscar por ID
return ['id' => $id, 'nome' => 'Usuário'];
}
// Diferença entre ?string e string|null (equivalente no PHP 8+)
function formatar(?string $texto): string {
return $texto ?? 'texto padrão';
}
// Cuidados com nullable - evite ambiguidades
function processar(?string $dado): void {
if ($dado === null) {
echo "Nenhum dado fornecido";
return;
}
echo "Processando: $dado";
}
// Combinação com valores padrão
function configurar(string $chave, mixed $valor = null): void {
if ($valor === null) {
// usar valor padrão do sistema
}
}
5. Tipos Union e Intersection (PHP 8+)
Os tipos union permitem que um parâmetro ou retorno aceite múltiplos tipos:
// Tipos union
function processarEntrada(int|string $entrada): string {
return match(true) {
is_int($entrada) => "Número: $entrada",
is_string($entrada) => "Texto: $entrada",
default => throw new \InvalidArgumentException()
};
}
function buscarRegistro(int|string $id): array|null {
// Aceita ID numérico ou string
}
// Tipos intersection (para classes e interfaces)
interface Logavel {}
interface Serializavel {}
class Logger implements Logavel, Serializavel {}
function processarLog(Logavel&Serializavel $objeto): void {
// $objeto deve implementar ambas interfaces
}
// Quando usar union vs herança
// Union é melhor para tipos não relacionados
function calcular(string|int|float $valor): float {
return (float) $valor;
}
// Herança para tipos relacionados
abstract class Forma {}
class Circulo extends Forma {}
class Quadrado extends Forma {}
function calcularArea(Forma $forma): float {
// polimorfismo
}
6. Tipos em Parâmetros Variadic e Named Arguments
Funções variadic podem receber um número variável de argumentos tipados:
// Tipagem em funções variadic
function somar(int ...$numeros): int {
return array_sum($numeros);
}
echo somar(1, 2, 3, 4, 5); // 15
function concatenar(string ...$partes): string {
return implode(' ', $partes);
}
// Comportamento com spread operator
$valores = [1, 2, 3];
echo somar(...$valores); // 6
// Named arguments e verificação de tipos
function configurarBD(
string $host,
int $porta = 3306,
string $usuario = 'root',
string $senha = ''
): void {
// configuração
}
// Chamada com named arguments
configurarBD(
host: 'localhost',
usuario: 'admin',
senha: '123456'
);
// Exemplo completo combinando variadic com tipagem
function processarTransacoes(
string $moeda,
float ...$valores
): array {
$total = array_sum($valores);
return [
'moeda' => $moeda,
'valores' => $valores,
'total' => $total,
'quantidade' => count($valores)
];
}
$resultado = processarTransacoes('BRL', 10.50, 25.00, 100.75);
7. Boas Práticas e Erros Comuns
// Sempre declarar tipos em funções públicas/API
// RUIM
function soma($a, $b) {
return $a + $b;
}
// BOM
function soma(int $a, int $b): int {
return $a + $b;
}
// Evitar mixed quando possível
// RUIM
function processar(mixed $dado): mixed {
return $dado;
}
// BOM (usar union)
function processar(string|int|array $dado): string|int|array {
return $dado;
}
// Tratamento de TypeError
function dividirSeguro(int $a, int $b): float {
if ($b === 0) {
throw new \DivisionByZeroError('Divisão por zero');
}
return $a / $b;
}
try {
echo dividirSeguro(10, 0);
} catch (\DivisionByZeroError $e) {
echo "Erro: " . $e->getMessage();
}
Uso de declare(strict_types=1):
declare(strict_types=1);
function somar(int $a, int $b): int {
return $a + $b;
}
// Isso causará TypeError, não conversão automática
// somar(5, '10'); // TypeError: Argument 2 must be of type int, string given
Dicas para migração de código legado:
1. Comece pelas funções mais críticas (API pública)
2. Use tipos nullable durante a transição
3. Adicione declare(strict_types=1) gradualmente
4. Utilize @param e @return em PHPDoc como documentação temporária
5. Teste exaustivamente após cada adição de tipo
Referências
- PHP Manual: Type Declarations — Documentação oficial completa sobre declaração de tipos em funções, incluindo parâmetros e retornos.
- PHP 8.0: Union Types — Explicação oficial sobre tipos union introduzidos no PHP 8.0, com exemplos práticos.
- PHP 8.1: Never Type — Documentação oficial sobre o tipo
neverpara funções que nunca retornam. - Strict Typing in PHP: A Complete Guide — Artigo técnico detalhado sobre tipagem estrita, declare(strict_types=1) e boas práticas.
- PHP Type System: Nullable Types — Explicação aprofundada sobre tipos nullable e seu funcionamento interno no PHP.
- PHP 8 Named Arguments — Documentação oficial sobre named arguments e como eles interagem com a tipagem de parâmetros.