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 { ... }
}
Ejemplo de código con genéricos:

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

Letra Significado Uso común
T Type El más usado
TKey Tipo de la clave En arrays, mapas
TValue Tipo del valor En colecciones
TEntity Tipo de entidad En repositorios
U, V Segundo y tercer tipo Cuando se necesitan varios

¿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.)
La "T" que se ve en los ejemplos es lo más importante de los genéricos

¿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 { ... }
}