Hablemos sobre covarianza y contravarianza > Blog | Josep Salvà - Desarrollo Web

La palabra de Wifft

La covarianza permite que el método hijo devuelva un tipo más específico que el tipo de devolución del método de su padre, mientras que la contravarianza permite que un tipo de parámetro sea menos específico en un método hijo, que el de su padre.

Por ejemplo, un caso de covarianza sería:

Si declaramos una interfaz, en este caso CarRental con un método rent, que en este caso devuelve una instancia de una supuesta clase abstracta llamada Car

interface CarRental
{
    public function rent(string $name): Car;
}

Al definir las clases que la implementen, podemos indicar tipos de retorno correspondientes a sub-clases más específicas (siempre que se extiendan de la que definimos en la interfaz o clase padre).

final class FooCarRental
{
    public function rent(string $name): Volvo
    {
        return new Volvo($name);
    }
}

final class BarCarRental
{
    public function rent(string $name): Porsche
    {
        return new Porsche($name);
    }
}

Para la contravarianza usaremos el mismo ejemplo:

interface CarRental
{
    public function rent(CarName $name): Car;
}

Al definir las clases que la implementen, podemos indicar tipos de parámetro correspondientes a clases padre menos específicas, hasta llegar al propio stdClass.

final class FooCarRental
{
    public function rent(ParentCarName $name): Volvo
    {
        return new Volvo($name);
    }
}

final class BarCarRental
{
    public function rent(object $name): Porsche
    {
        return new Porsche($name);
    }
}

Es importante destacar que, la covarianza solo se aplica a tipos de retorno de métodos y la contravarianza solo se aplica a tipos de parámetros de métodos.