Doc #79538 [Com]: Incomplete example in language.oop5.variance
| From: | tiffany@php.net | 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