ОНОВЛЕННЯ : PHP 7.4 тепер підтримує коваріацію та контраваріацію, які вирішують основну проблему, порушену в цьому питанні.
Я зіткнувся з якоюсь проблемою із використанням підказки типу return у PHP 7. Я розумію, що підказка : self
означає, що ви маєте намір повернути сам клас-реалізатор. Тому я використовував : self
у своїх інтерфейсах це вказувати, але коли я намагався насправді реалізувати інтерфейс, у мене з'явилися помилки сумісності.
Далі - проста демонстрація проблеми, з якою я зіткнувся:
interface iFoo
{
public function bar (string $baz) : self;
}
class Foo implements iFoo
{
public function bar (string $baz) : self
{
echo $baz . PHP_EOL;
return $this;
}
}
(new Foo ()) -> bar ("Fred")
-> bar ("Wilma")
-> bar ("Barney")
-> bar ("Betty");
Очікуваний результат був:
Фред Вілма Барні Бетті
Я насправді отримую:
Фатальна помилка PHP: Декларація Foo :: bar (int $ baz): Foo повинен бути сумісним з iFoo :: bar (int $ baz): iFoo у test.php у рядку 7
Річ у тому, що Foo - це реалізація iFoo, тому, наскільки я можу зрозуміти, реалізація повинна бути повністю сумісною з даним інтерфейсом. Можливо, я міг би вирішити цю проблему, змінивши або інтерфейс, або клас реалізації (або обидва), щоб повернути підказку про інтерфейс за іменем, замість використання self
, але я розумію, що семантично self
означає "повернути екземпляр класу, який ви щойно викликали методом ". Тому зміна його на інтерфейс теоретично означало б, що я міг би повернути будь-який екземпляр чогось, що реалізує інтерфейс, коли я маю намір викликаний екземпляр - це те, що буде повернуто.
Це недогляд у PHP чи це свідоме дизайнерське рішення? Якщо це перший, чи є шанс побачити це виправленим у PHP 7.1? Якщо ні, то який правильний спосіб повернення натякаючи, що ваш інтерфейс очікує, що ви повернете екземпляр, для якого ви щойно викликали метод, для ланцюжка?