Introdução: o que são Generics e por que são importantes em PHP
O desenvolvimento moderno em PHP exige cada vez mais tipagem estrita e código reutilizável. Uma das ferramentas-chave para atingir esses objetivos são os Generics (generalizações ou genéricos). Em PHP, o suporte a Generics foi oficialmente adicionado a partir da versão PHP 8.0, embora anteriormente existissem várias utilidades e anotações (por exemplo, via PHPDoc).
Neste artigo, vamos analisar para que servem os Generics em PHP, como funcionam na prática e fornecer exemplos de código específicos que ajudarão você a escrever um código mais seguro, legível e escalável.
Para que servem os Generics em PHP?
O principal objetivo dos Generics é garantir a segurança de tipos durante a execução, sem perder a flexibilidade do código genérico. Imagine que você está escrevendo uma função para trabalhar com uma coleção de elementos. Sem Generics, você ou usa tipos mistos (mixed) ou escreve funções separadas para cada tipo de dado. Ambas as abordagens levam a erros e duplicação de código.
Aqui estão as principais vantagens de usar Generics:
- Segurança de tipos — erros de tipo são detectados em tempo de compilação, não em tempo de execução.
- Reutilização de código — uma única função ou classe funciona com qualquer tipo de dado.
- Legibilidade — o código se torna autodocumentado: fica imediatamente claro quais tipos são aceitos e retornados.
- Integração com IDE — editores modernos (PhpStorm, VS Code) entendem melhor o código com Generics, oferecendo autocompletar e sugestões.
Como funcionam os Generics em PHP: sintaxe e construções principais
Em PHP, os Generics são implementados por meio de modelos de tipos, que são definidos entre colchetes angulares <T>. A letra T é uma designação condicional para o tipo que será substituído ao chamar a função ou criar o objeto. Você pode usar qualquer nome: T, K, V ou nomes significativos.
1. Funções genéricas
Vamos considerar um exemplo simples — uma função que retorna o primeiro elemento de um array:
<?php
function firstElement(array $items): mixed { return $items[0] ?? null;}
// Uso$numbers = [1, 2, 3];$first = firstElement($numbers); // tipo mixed, IDE não sabe que é intCom Generics, podemos especificar que a função trabalha com um array de elementos de qualquer tipo, mas retorna exatamente o tipo que foi passado:
<?php
/** * @template T * @param array<T> $items * @return T|null */function firstElement(array $items): mixed { return $items[0] ?? null;}
// Agora a IDE entende que $first é int|null$first = firstElement([1, 2, 3]);Observe: no PHP 8.0+, os Generics são suportados por meio de anotações PHPDoc. O suporte nativo (sem comentários) ainda não existe, mas este é o padrão de facto para projetos modernos.
2. Classes genéricas
O cenário mais comum de uso de Generics são as classes de coleção. Vamos criar uma classe simples Collection que pode armazenar elementos de qualquer tipo:
<?php
/** * @template T */class Collection { /** @var array<T> */ private array $items = [];
/** * @param T $item * @return void */ public function add(mixed $item): void { $this->items[] = $item; }
/** * @return T|null */ public function get(int $index): mixed { return $this->items[$index] ?? null; }
/** * @return array<T> */ public function all(): array { return $this->items; }}
// Uso$intCollection = new Collection<int>();$intCollection->add(10);$intCollection->add(