Kovarians och kontravarians
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 typ tas bort från en unionstyp
- En typ läggs till i en intersectionstyp
- En klass-typ ändras till en barnklass-typ
- iterable ändras till array eller Traversable
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/