DPhil
@DPhil
Контент-менеджер

Почему в php нельзя уточнить класс аргумента при имплементации интерфейса?

1. Определяем интерфейс

interface TestInterface 
{
    public function testMethod(ArgInterface $arg);
}

2. Определяем ArgInterface
interface ArgInterface
{
}

3. Имплементируем ArgInterface:
class Arg implements ArgInterface
{
	public $id;
}

4. Имплементируем TestInterface, но $arg уточняем тип с ArgInterface на Arg, который реализует ArgInterface
class Test implements TestInterface
{
    public function testMethod(Arg $arg) 
    {
        echo $arg->id;
    }
}

Запускаем:
<?php

interface TestInterface 
{
    public function testMethod(ArgInterface $arg);
}

interface ArgInterface
{
}

class Arg implements ArgInterface
{
	public $id;
}

class Test implements TestInterface
{
    public function testMethod(Arg $arg) 
    {
        echo $arg->id;
    }
}

$arg = new Arg();
$arg->id = 1;

$test = new Test();
$test->testMethod($arg);

Ничего работать не будет:
Fatal error: Declaration of Test::testMethod(Arg $arg) must be compatible with TestInterface::testMethod(ArgInterface $arg) in /home/user/scripts/code.php on line 18

Почему? Мы же уточняем тайпхинтинг наследником (имплементирующим классом), то есть принцип Лисков должен пропускать. Наследник же сохраняет всю функциональность родителя.

Есть ли этому поведению рациональное объяснение или это особенность языка?
  • Вопрос задан
  • 257 просмотров
Решения вопроса 2
Потому что это бы нарушало принцип подстановки Барбары Лисков.

Интерфейс предполагает, что ты можешь принимать любой объект, который реализует интерфейс ArgInterface.
=> Если ты сузишь тип, то ты уже по факту не сможешь поддерживать контракт.

По тому при реализации интерфейса можно только расширять тип принимаемых аргументов, но не сужать.
Ответ написан
Комментировать
LSP нарушается - интерфейс требует чтобы реализация в качестве аргумента могла принимать любую реализацию ArgInterface, а вы пытаетесь ограничится только одной.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы