Doc #79538 [Csd->Nab]: Incomplete example in language.oop5.variance
| From: | cmb@php.net | Date: | Wed, 29 Apr 2020 16:40:52 +0000 |
| Subject: | Doc #79538 [Csd->Nab]: Incomplete example in language.oop5.variance | ||
| References: | 1 | Groups: | php.doc.bugs |
| Request: | Send a blank email to doc-bugs+get-17535@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: Incomplete example in language.oop5.variance
-Status: Closed
+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
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