Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding argument type in interface implementation

Tags:

oop

php

Let's assume I have a Model Interface:

interface Model
{
}

And a function in an interface which receives that Model as a param:

interface Service
{
    public function add(Model $model);
}

Why is it, that when I implement that Service with another Model that implements the above like this:

class AnotherModel implements Model
{
}

class AnotherService implements Service
{
    public function add(AnotherModel $model);
}

I get this error:

Fatal error: Declaration of AnotherService::add() must be compatible with Service::add(Model $model)

like image 388
Jacob Cohen Avatar asked Feb 09 '23 13:02

Jacob Cohen


1 Answers

When you extend a class or implement an interface you are not allowed to make any type or visibility constraints of inherited methods more strict than in the parent. It means that if you have a public method in the parent you are not allowed to make it protected/private. And if a parent method accepts arguments of some specific type (Model in this case), you are not allowed to limit arguments it accepts to some more specific type.

That's what you are doing here - your Service::add() accepts elements of type Model, but the implementation in AnotherService accepts ONLY objects of type AnotherModel. It means that even if you have another class that implements Model, e.g. "class YetAnotherModel implements Model", AnotherService::add() won't accept it as YetAnotherModel is not an instance of AnotherModel, even though they implement the same interface. So AnotherService::add() won't accept object of YetAnotherModel class even though you implement Service interface that says "I accept all Models in my add() method".

Please see https://en.wikipedia.org/wiki/Liskov_substitution_principle for more details.

like image 87
jedrzej.kurylo Avatar answered Feb 12 '23 04:02

jedrzej.kurylo