Generics em PHP: guia completo de tipagem com exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que Generics não são apenas uma tendência, mas uma necessidade?

\n\n

Se você já escreveu código PHP que trabalhava com coleções, repositórios ou camadas de serviço, certamente já passou por esta situação: a função aceita um array, mas o que tem dentro é um mistério. Podem ser usuários, podem ser gatos. Ou, pior ainda, os dois juntos. É exatamente aqui que os Generics entram em cena — uma ferramenta poderosa de tipagem que torna seu código previsível, seguro e autodocumentado.

\n\n

Neste artigo, vamos explorar como os generics funcionam no PHP, por que você precisa deles e como usá-los em projetos reais. Você aprenderá a evitar erros comuns e a escrever um código mais profissional. Vamos nessa!

\n\n

O que são Generics em termos simples?

\n\n

Imagine que você é um desenvolvedor de e-commerce. Você tem uma classe Carrinho que armazena produtos. Sem generics, você escreve:

\n\n
class Carrinho {\n    private array $itens;\n    \n    public function adicionarItem($item): void {\n        $this->itens[] = $item;\n    }\n    \n    public function getItens(): array {\n        return $this->itens;\n    }\n}
\n\n

Qual o problema? $item pode ser qualquer coisa — número, string, objeto Produto ou até null. A IDE não consegue sugerir qual tipo é retornado por getItens(). Você vai ter que consultar a documentação ou debugar.

\n\n

Generics resolvem isso. Eles permitem que você especifique: "Ei, esta classe só trabalha com produtos!". Fica assim:

\n\n
class Carrinho {\n    /** @param Produto[] $itens */\n    private array $itens;\n    \n    public function adicionarItem(Produto $item): void {\n        $this->itens[] = $item;\n    }\n    \n    /** @return Produto[] */\n    public function getItens(): array {\n        return $this->itens;\n    }\n}
\n\n

Mas isso é apenas uma simulação. Os generics reais no PHP surgiram com o PHP 8.0, e o suporte completo veio no PHP 8.1+ com atributos e análise estática (como PHPStan ou Psalm).

\n\n

Como os Generics funcionam de verdade no PHP?

\n\n

Ao contrário de Java ou C#, o PHP não possui suporte nativo a generics no nível de sintaxe (por enquanto). No entanto, graças às anotações PHPDoc e ferramentas de análise estática, podemos obter todos os benefícios da tipagem.

\n\n

Tipos Template (Template Types)

\n\n

A abordagem mais popular é usar @template no PHPDoc. Veja um exemplo com uma coleção:

\n\n
/**\n * @template T\n */\nclass Colecao {\n    /** @var array<int, T> */\n    private array $itens = [];\n    \n    /**\n     * @param T $item\n     */\n    public function adicionar(mixed $item): void {\n        $this->itens[] = $item;\n    }\n    \n    /**\n     * @return T\n     */\n    public function get(int $indice): mixed {\n        return $this->itens[$indice] ?? throw new \\OutOfBoundsException();\n    }\n}
\n\n

Agora, ao usar esta classe, você especifica o tipo concreto:

\n\n
/** @var Colecao<Usuario> $colecaoUsuarios */\n$colecaoUsuarios = new Colecao();\n$colecaoUsuarios->adicionar(new Usuario('Alice'));\n$usuario = $colecaoUsuarios->get(0); // PHPStan sabe: $usuario é do tipo Usuario\necho $usuario->nome; // Seguro!
\n\n

Restrições (Constraints) para Generics

\n\n

Às vezes, você precisa que o tipo T não seja qualquer um, mas que implemente uma interface específica. Isso é chamado de bound (restrição):

\n\n
/**\n * @template T of \\JsonSerializable\n */\nclass ColecaoJson {\n    /** @var array<int, T> */\n    private array $itens = [];\n    \n    public function paraJson(): string {\n        return json_encode($this->itens);\n    }\n}
\n\n

Agora você não conseguirá adicionar um objeto que não implemente JsonSerializable à coleção. A IDE e o analisador estático exibirão um erro.

\n\n

Exemplos práticos: do simples ao complexo

Blogs

Book Recommendations