Допустим, у меня есть конкретная модель, которая расширяется от «модели»
Class MyModel extends Model { ... }
Для каждой модели я хочу создать класс Translator, который реализует TranslatorInterface.
Interface TranslatorInterface {
public function translate(Model $model);
}
Но вместо передачи родительского класса Model я хочу передать точную дочернюю модель в метод translate.
Class MyTranslator implements TranslatorInterface {
public function translate(MyModel $model) {
...
}
}
И я не могу заставить это работать.
Я знаю, что могу обойти это
Class MyTranslator implements TranslatorInterface {
public function __construct(MyModel $model) {
$this->model = $model;
}
public function translate() {
$this->model->doSomething();
...
}
}
И метод интерфейса __construct не определен, и метод translate () также не получает никаких аргументов.
Но мне интересно, есть ли возможность сделать это так, как я пробовал выше (а если нет, и это задумано, почему это плохая идея;))






С точки зрения ООП: вы меняете сигнатуру функции:
В реализации также следует использовать:
public function translate(Model $model){}
И вы можете передать этой функции аргументы типа MyModel.
Все MyModel являются Model, но не все Model являются MyModel, у вас могут быть другие реализации Model, которые могут быть переданы функции, но не MyModel.
РЕДАКТИРОВАТЬ1: Согласно вашему комментарию ниже:
вы можете проверить каждую имплементацию, если она является экземпляром требуемого класса:
Class MyTranslator implements TranslatorInterface {
public function translate(Model $model) {
if (is_a($model, 'MyModel')) {
echo "yes, you use to translate MyModel \n";
}
}
}
В зависимости от контекста вы можете использовать это решение, но я думаю, что решение с использованием _constructor - лучший способ сделать это с небольшим изменением:
Class MyTranslator implements TranslatorInterface {
public function __construct(Model $model) {
$this->model = $model;
}
public function translate() {
$this->model->doSomething();
...
}
}
Вам нужен только один конструктор, и он будет использовать правильную имплементацию, основанную на полиморфизме.
Это запрещено, поскольку нарушает Принцип замены Лискова:
Contravariance of method arguments in the subtype.
Это означает, что метод можно изменить, но только если вы расширите ограничение типа. На данный момент PHP не поддерживает настоящий контравариантность. В настоящее время вы можете использовать только простой расширение типа параметра - это означает, что в реализации интерфейса вы можете опустить тип параметра.
Что ж, это мой вопрос ... Скажем, у меня есть 3 дочерних элемента ModelA, ModelB и ModelC. И для каждой модели у меня есть собственный переводчик TranslatorA, B и C также. ВНИМАНИЕ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Все переводчики могут просто обрабатывать конкретную модель TranslatorA, просто ModelA и так далее, но для этого необходима функция translate (). И я хочу предотвратить передачу неправильной модели в качестве аргумента, но хочу сказать, что, по крайней мере, в интерфейсе это должен быть какой-то родительский тип. Кажется, это невозможно? Я знаю, что это редкий случай, и еще один обходной путь / дополнение к моему решению - это TranslatorFactory - просто интересно, почему это запрещено.