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
Почему? Мы же уточняем тайпхинтинг наследником (имплементирующим классом), то есть принцип Лисков должен пропускать. Наследник же сохраняет всю функциональность родителя.
Есть ли этому поведению рациональное объяснение или это особенность языка?