Reputation: 2749
Let's say I've got a specific model which extends from a "model"
Class MyModel extends Model { ... }
For each model I want to create a Translator class which implements the TranslatorInterface
Interface TranslatorInterface {
public function translate(Model $model);
}
But instead of passing the parent class "Model" I want to pass the exact model child into the translate method
Class MyTranslator implements TranslatorInterface {
public function translate(MyModel $model) {
...
}
}
And I can't get this working.
I know I can workaround this by
Class MyTranslator implements TranslatorInterface {
public function __construct(MyModel $model) {
$this->model = $model;
}
public function translate() {
$this->model->doSomething();
...
}
}
And the interface __construct method isn't defined and the translate() method doesn't receive any args as well.
But I'm wondering if there is a possibility to get it done like I tried above.(And if not and it's intended why this is a bad idea ;))
Upvotes: 2
Views: 312
Reputation: 3802
This is forbidden because it violates Liskov Substitution Principle:
Contravariance of method arguments in the subtype.
This means that the method can be changed, but only if you widen the type restriction. For now, PHP doesn't support real contravariance. At this time you can only use simple parameter type widening -- meaning that in the implementation of the interface you can omit parameter type.
Upvotes: 2
Reputation: 333
From OOP point of view: you are changing the function signature:
In implementation you should also use:
public function translate(Model $model){}
And you can pass arguments of type MyModel to this function.
All MyModel are Model, but not all Model are MyModel, you can have other implementations of Model, which can be passed to the function, but are not MyModel.
EDIT1 : According to your comment bellow:
you could check in each implimentation if it is a instace of the required class:
Class MyTranslator implements TranslatorInterface {
public function translate(Model $model) {
if (is_a($model, 'MyModel')) {
echo "yes, you use to translate MyModel \n";
}
}
}
Depending on the context you can use this solution, but i think solution using the _constructor is better approach of doing this with a small change:
Class MyTranslator implements TranslatorInterface {
public function __construct(Model $model) {
$this->model = $model;
}
public function translate() {
$this->model->doSomething();
...
}
}
You need only one constructor, and it will use the right implimentation based on Polimorphism.
Upvotes: 1