Kovarians och kontravarians

Från Wiki.linux.se
Version från den 19 augusti 2024 kl. 05.46 av Admin (diskussion | bidrag) (→‎Kovarians och kontravarians)
(skillnad) ← Äldre version | Nuvarande version (skillnad) | Nyare version → (skillnad)
Hoppa till navigering Hoppa till sök

Kovarians och kontravarians

I PHP 7.2.0 introducerades partiell kontravarians genom att ta bort typrestriktioner för parametrar i en barnmetod. Från och med PHP 7.4.0 lades fullt stöd för kovarians och kontravarians till.

Kovarians tillåter att en barns metod returnerar en mer specifik typ än returtypen för dess förälders metod. Kontravarians å andra sidan tillåter att en parametertyp är mindre specifik i en barns metod än i dess förälders metod.

En typdeklaration anses vara mer specifik i följande fall:

En typklass anses vara mindre specifik om motsatsen är sann.

Kovarians

För att illustrera hur kovarians fungerar skapas en enkel abstrakt föräldraklass, Animal. Animal kommer att utökas av barnklasserna Cat och Dog.

<?php

abstract class Animal
{
    protected string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    abstract public function speak();
}

class Dog extends Animal
{
    public function speak()
    {
        echo $this->name . " skäller";
    }
}

class Cat extends Animal 
{
    public function speak()
    {
        echo $this->name . " jamar";
    }
}

Observera att det inte finns några metoder som returnerar värden i detta exempel. Några fabriker kommer att läggas till som returnerar ett nytt objekt av klassen Animal, Cat, eller Dog.

<?php

interface AnimalShelter
{
    public function adopt(string $name): Animal;
}

class CatShelter implements AnimalShelter
{
    public function adopt(string $name): Cat // istället för att returnera klass-typen Animal, kan den returnera klass-typen Cat
    {
        return new Cat($name);
    }
}

class DogShelter implements AnimalShelter
{
    public function adopt(string $name): Dog // istället för att returnera klass-typen Animal, kan den returnera klass-typen Dog
    {
        return new Dog($name);
    }
}

$kitty = (new CatShelter)->adopt("Ricky");
$kitty->speak();
echo "\n";

$doggy = (new DogShelter)->adopt("Mavrick");
$doggy->speak();

Ovanstående exempel kommer att ge följande utskrift:

Ricky jamar
Mavrick skäller

Kontravarians

Vi fortsätter med föregående exempel med klasserna Animal, Cat, och Dog. En klass som heter Food och AnimalFood kommer att inkluderas, och en metod `eat(AnimalFood $food)` läggs till i den abstrakta klassen Animal.

<?php

class Food {}

class AnimalFood extends Food {}

abstract class Animal
{
    protected string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function eat(AnimalFood $food)
    {
        echo $this->name . " äter " . get_class($food);
    }
}

För att visa hur kontravarians fungerar, överskrids metoden `eat` i klassen Dog för att tillåta vilken Food-typ som helst. Klassen Cat förblir oförändrad.

<?php

class Dog extends Animal
{
    public function eat(Food $food) {
        echo $this->name . " äter " . get_class($food);
    }
}

Nästa exempel kommer att visa hur kontravarians fungerar.

<?php

$kitty = (new CatShelter)->adopt("Ricky");
$catFood = new AnimalFood();
$kitty->eat($catFood);
echo "\n";

$doggy = (new DogShelter)->adopt("Mavrick");
$banana = new Food();
$doggy->eat($banana);

Ovanstående exempel kommer att ge följande utskrift:

Ricky äter AnimalFood
Mavrick äter Food

Men vad händer om `$kitty` försöker äta `$banana`?

$kitty->eat($banana);

Ovanstående exempel kommer att ge följande utskrift:

Fatal error: Uncaught TypeError: Argument 1 passed to Animal::eat() must be an instance of AnimalFood, instance of Food given

Sidslut

Orginalhemsidan på Engelska : https://www.php.net/manual/en/language.oop5.variance.php
PHP
Språkreferens
Språkreferens#Klasser_och_Objekt


Det här är en maskinöversättning av PHP-manualen till svenska. Om du hittar fel är vi tacksamma om du rapporterar dem via formuläret som finns på https://www.linux.se/kontaka-linux-se/