Doc #79538 [Opn->Ver]: Incomplete example in language.oop5.variance

From: Date: Wed, 29 Apr 2020 15:44:42 +0000
Subject: Doc #79538 [Opn->Ver]: Incomplete example in language.oop5.variance
References: 1  Groups: php.doc.bugs 
Request: Send a blank email to doc-bugs+get-17533@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=79538&edit=1 ID: 79538 Updated by: cmb@php.net Reported by: david at codepoets dot co dot uk -Summary: Incorrect type hint in language.oop5.variance +Summary: Incomplete example in language.oop5.variance -Status: Open +Status: Verified Type: Documentation Problem Package: Documentation problem Operating System: n/a PHP Version: Irrelevant Block user comment: N Private report: N New Comment: > The eat method should instead take Food as a type hint, and not > AnimalFood. That would defeat the purpose of the example, though, because it is about contravariance, not invariance. The problem is that Cat::eat() is not defined. See <https://3v4l.org/14rTK> for a working example. Previous Comments: ------------------------------------------------------------------------ [2020-04-29 12:12:24] david at codepoets dot co dot uk Description: ------------ --- From manual page: https://php.net/language.oop5.variance --- in the Contravariance section there is : abstract class Animal { protected string $name; public function __construct(string $name) { $this->name = $name; } public function eat(AnimalFood $food) { echo $this->name . " eats " . get_class($food); } } The eat method should instead take Food as a type hint, and not AnimalFood. i.e. something more like : abstract class Animal { ..... public function eat(Food $food) { echo $this->name . " eats " . get_class($food); } } Test script: --------------- <?php abstract class Animal { protected $name; public function __construct(string $name) { $this->name = $name; } abstract public function speak(); public function eat(AnimalFood $food) { echo $this->name . " eats " . get_class($food); } } class Dog extends Animal { public function speak() { echo $this->name . " barks"; } } class Cat extends Animal { public function speak() { echo $this->name . " meows"; } } interface AnimalShelter { public function adopt(string $name): Animal; } class CatShelter implements AnimalShelter { public function adopt(string $name): Cat // instead of returning class type Animal, it can return class type Cat { return new Cat($name); } } class DogShelter implements AnimalShelter { public function adopt(string $name): Dog // instead of returning class type Animal, it can return class type Dog { return new Dog($name); } } class Food {} class AnimalFood extends Food {} $kitty = (new CatShelter)->adopt("Ricky"); $catFood = new AnimalFood(); $kitty->eat($catFood); echo "\n"; $doggy = (new DogShelter)->adopt("Mavrick"); $banana = new Food(); $doggy->eat($banana); Expected result: ---------------- Ricky eats AnimalFood Mavrick eats Food Actual result: -------------- david@walnut:~/src/php-library/animals$ php7.4 animals.php Ricky eats AnimalFood PHP Fatal error: Uncaught TypeError: Argument 1 passed to Animal::eat() must be an instance of AnimalFood, instance of Food given, called in /home/david/src/php-library/animals/animals.php on line 75 and defined in /home/david/src/php-library/animals/animals.php:15 Stack trace: #0 /home/david/src/php-library/animals/animals.php(75): Animal->eat() #1 {main} thrown in /home/david/src/php-library/animals/animals.php on line 15 ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=79538&edit=1

« previous php.doc.bugs (#17533) next »