Generics en PHP: para qué sirven y cómo usarlos
El desarrollo moderno en PHP requiere no solo velocidad, sino también confiabilidad del código. Una de las herramientas que ayuda a lograr este objetivo son los Generics (tipos genéricos). A pesar de que PHP es un lenguaje de tipado dinámico, con la llegada de PHP 7.0 y superiores, y especialmente con PHP 8.0, el tipado estático se ha vuelto accesible y demandado. Los Generics permiten escribir estructuras de datos más flexibles, reutilizables y seguras, como colecciones, pilas, colas y repositorios, sin perder información sobre los tipos.
En este artículo, analizaremos en detalle qué son los Generics en PHP, para qué sirven, cómo usarlos correctamente en la práctica y veremos ejemplos concretos de código.
¿Qué son los Generics y para qué sirven?
Generics (tipos genéricos) es un mecanismo que permite parametrizar clases, interfaces, traits y funciones con un tipo de dato. En lugar de escribir una implementación separada para cada tipo (por ejemplo, IntegerList, StringList, UserList), se crea una clase universal List<T>, donde T es un placeholder (sustituto) para el tipo concreto que se pasará al usarlo.
¿Para qué sirve?
- Seguridad de tipos: Los IDE y analizadores estáticos (Psalm, PHPStan) pueden verificar que en la colección solo entren elementos de un mismo tipo, previniendo errores en la etapa de desarrollo.
- Reducción de duplicación de código: No es necesario escribir la misma clase para diferentes tipos de datos.
- Mejora de la legibilidad: El código se vuelve autodocumentado: se ve inmediatamente qué tipos de datos se esperan.
- Aumento del rendimiento: Aunque PHP en sí mismo no usa Generics a nivel de máquina virtual (como Java o C#), los analizadores estáticos ayudan a encontrar errores potenciales antes de la ejecución del código.
¿Cómo usar Generics en PHP? Sintaxis y ejemplos
A partir de PHP 8.0, se introdujo soporte para Generics a nivel de anotaciones (docblock) y parcialmente a nivel de código (para variadic arguments). Se espera soporte completo a nivel de sintaxis en versiones futuras, pero ya ahora se pueden usar Generics de manera efectiva con PHPDoc y analizadores estáticos.
1. Sintaxis básica con PHPDoc
La forma más común es usar las anotaciones @template y @param/@return indicando el tipo genérico.
<?php
/** * @template T */class Collection { /** @var array<T> */ private array $items;
/** * @param T $item */ public function add($item): void { $this->items[] = $item; }
/** * @return T|null */ public function get(int $index) { return $this->items[$index] ?? null; }}
// Ejemplo de uso$intCollection = new Collection();$intCollection->add(42);// $intCollection->add('string'); // Error del analizador estático
$userCollection = new Collection();$userCollection->add(new User());// $userCollection->add(123); // Error?>En este ejemplo, @template T declara el tipo genérico. @param T $item y @return T|null le indican al analizador que el tipo de los elementos debe ser consistente.
2. Restricciones de tipos (bounded generics)
Se puede restringir qué tipos pueden usarse como parámetro. Esto se hace con @extends o @implements.
<?php
/** * @template T of \\Stringable */class StringableCollection { /** @var array<T> */ private array $items;
/** * @param T $item */ public function add($item): void { $this->items[] = $item; }```