Doc #79538 [Com]: Incomplete example in language.oop5.variance

From: Date: Wed, 29 Apr 2020 16:53:47 +0000
Subject: Doc #79538 [Com]: Incomplete example in language.oop5.variance
References: 1  Groups: php.doc.bugs 
Request: Send a blank email to doc-bugs+get-17536@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 Comment by: tiffany@php.net Reported by: david at codepoets dot co dot uk Summary: Incomplete example in language.oop5.variance Status: Not a bug Type: Documentation Problem Package: Documentation problem Operating System: n/a PHP Version: Irrelevant Assigned To: cmb Block user comment: N Private report: N New Comment: The examples are a bit silly (intentionally), they're written as a play on dogs eating almost anything, and cats being picky eaters. The Cat class inherits the eat() method from Animal, which only accepts AnimalFood. The eat() method inside Dog overrides Animal::eat() so it can eat any kind of Food, which is how contravariance works - the child method accepts a less specific parameter than its parent. The error you receive is documented near the bottom when $kitty tries to eat() the $banana. Previous Comments: ------------------------------------------------------------------------ [2020-04-29 16:40:43] cmb@php.net > The problem is that Cat::eat() is not defined. Nope. Actually, there is no problem. ------------------------------------------------------------------------ [2020-04-29 15:44:42] cmb@php.net > 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. ------------------------------------------------------------------------ [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 (#17536) next »