I have the following OOP structure:
<?php
interface AnimalInterface
{
public function getName();
}
class Dog implements AnimalInterface
{
public function getName() {
return 'dog';
}
public function makeFriends()
{
echo 'I have friends now :)';
}
}
class Cat implements AnimalInterface
{
public function getName() {
return 'cat';
}
public function hateFriends()
{
echo 'I cant make friends :(';
}
}
interface AnimalDoInterface
{
public function makeFriend(AnimalInterface $animal);
}
class DogFriend implements AnimalDoInterface
{
public function makeFriend(Dog $dog)
{
$dog->makeFriends();
}
}
class CatFriend implements AnimalDoInterface
{
public function makeFriend(Cat $cat)
{
$cat->hateFriends();
}
}
Now PHP's manual on Object Interfaces says:
The class implementing the interface must use the exact same method signatures as are defined in the interface. Not doing so will result in a fatal error.
Why is this the case? Am I misunderstanding interfaces completely? Surely I should be able to declare AnimalDoInterface::makeFriend with anything that is the interface or an implementation of that interface? In this case it should technically be compatible as Cat implements AnimalInterface, which is what it's expecting.
Regardless of whether I am getting my OOP wrong, is there a way to implement this in PHP?
So it seems I wasn't clear enough, my bad for that. However, basically what I'm trying to achieve is to have the implementations of AnimalDoInterface to be more restrictive than it's interface says. So in this case, I'd like DogFriend::makeFriend to only allow the Dog class as it's argument, which in my mind should be acceptable as it implements the AnimalInterface, and the CatFriend to allow a Cat class, which again, same thing.
EDIT: fixed the classes, also added what I'm trying to achieve.
EDIT 2:
So at the moment, the way I'd have to implement it is as following:
class DogFriend implements AnimalDoInterface
{
public function makeFriend(AnimalInterface $dog)
{
if(!($dog instanceof Dog)) {
throw new \Exception('$dog must be of Dog type');
}
$dog->makeFriends();
}
}
class CatFriend implements AnimalDoInterface
{
public function makeFriend(AnimalInterface $cat)
{
if(!($dog instanceof Cat)) {
throw new \Exception('$dog must be of Cat type');
}
$cat->hateFriends();
}
}
I'd like to have to avoid this extra check for the class type.
Fatal error: Class Dog contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (AnimalInterface::getAnimalName)AnimalInterfaceclasses doesn't have the methodgetAnimalName()which is abstract. And must be used. Remember all interfaces methods itself are abstract and must be implemented within a class