GENÉRICOS EN PHP: QUÉ SON Y CÓMO UTILIZARLOS
Los genéricos en PHP son una funcionalidad que permite crear código reutilizable y type-safe,seguro a nivel de tipos, para clases, interfaces, funciones y métodos que trabajan con diferentes tipos de datos.¿Qué son exactamente los genéricos?
Los genéricos permiten definir un componente, como una clase, con parámetros de tipo, placeholders, en lugar de fijar un tipo concreto.Ejemplo de código sin genéricos:
class UserCollection {
public function add(User $user): void { ... }
public function get(int $index): User { ... }
}
class ProductCollection {
public function add(Product $product): void { ... }
public function get(int $index): Product { ... }
}
class Collection { // es el parámetro de tipo
/** @var array */
private array $items = [];
public function add(T $item): void { ... }
/** @return T */
public function get(int $index): mixed { ... }
}
//usarlo así
$users = new Collection();
$products = new Collection();
Convenciones más usadas
¿Qué aporta?
- Mejor autocompletado en el IDE
- Detección temprana de errores de tipo
- Código mucho más limpio y reutilizable
- Usado intensamente en frameworks modernos (Laravel, Symfony, Doctrine, etc.)
¿Qué es la "T"?
"T" es un parámetro de tipo (type parameter). Es como una variable pero para tipos. En lugar de poner un tipo concreto (User, Product, string, int, etc.), se pone "T" como un "comodín" que luego será reemplazado por un tipo real cuando se use la clase.Ejemplos
/**
* @template T ← Aquí declaramos que esta clase va a usar un tipo llamado T
*/
class Collection
{
/**
* @var array ← El array contendrá elementos del tipo T
*/
private array $items = [];
/**
* @param T $item ← Acepta cualquier cosa del tipo T
*/
public function add(mixed $item): void
{
$this->items[] = $item;
}
/**
* @return T ← Devuelve un elemento del tipo T
*/
public function get(int $index): mixed
{
return $this->items[$index];
}
}
Cómo se usa en la práctica
$usuarios = new Collection(); // Aquí T puede ser cualquier cosa
// Mejor usarlo así (con anotación):
/** @var Collection */
$usuarios = new Collection();
$usuarios->add(new User()); // Correcto
$usuarios->add("texto"); // PHPStan te avisará de error
//Ahora "T" se convierte en "User".
Si se crea otra colección:
/** @var Collection */
$productos = new Collection();
$productos->add(new Product());
//En este caso "T" se convierte en "Product".
Ejemplo con varios tipos
/**
* @template TKey
* @template TValue
*/
class Dictionary
{
/** @param TKey $key */
/** @param TValue $value */
public function set(mixed $key, mixed $value): void { ... }
}
$usuarios = new Collection(); // Aquí T puede ser cualquier cosa
// Mejor usarlo así (con anotación):
/** @var Collection */
$usuarios = new Collection();
$usuarios->add(new User()); // Correcto
$usuarios->add("texto"); // PHPStan te avisará de error
//Ahora "T" se convierte en "User".
/** @var Collection */
$productos = new Collection();
$productos->add(new Product());
//En este caso "T" se convierte en "Product".
Ejemplo con varios tipos
/**
* @template TKey
* @template TValue
*/
class Dictionary
{
/** @param TKey $key */
/** @param TValue $value */
public function set(mixed $key, mixed $value): void { ... }
}