Подсказки типа php не ладят с интерфейсами и абстрактными классами? - PullRequest
16 голосов
/ 31 декабря 2010

Я думаю, что будет гораздо проще увидеть проблему в примере кода, чем сначала написать вопрос. Вот мой php код:

<?php

interface AnInterface
{
        public function method();
}    

class AClass implements AnInterface
{
        public function method()
        {
                echo __METHOD__;
        }
}    

abstract class AnAbstractClass
{
        abstract public function method( AnInterface $Object );
}

class ConcreteClass extends AnAbstractClass
{
        public function method( AClass $Object )
        {
                $Object->method();
        }
}

$Object1 = new ConcreteClass();
$Object2 = new AClass();

$Object1->method( $Object2 );

Приведенный выше код вызывает следующую ошибку:

Неустранимая ошибка: объявление ConcreteClass :: method () должно быть совместимо с объявлением AnAbstractClass :: method ()

Проблема в том, что php, похоже, не распознает сигнатуры AnAbstractClass :: method и ConcreteClass :: method как совместимые. Я делаю что-то неправильно? Спасибо!

Ответы [ 3 ]

26 голосов
/ 31 декабря 2010

php не распознает подписи AnAbstractClass::method и ConcreteClass::method как совместимые.

PHP верен, они не совместимы. Допуская, чтобы только экземпляры AClass (или его дочерние элементы) передавались в ConcreteClass::method, вы нарушаете контракт, который обеспечивает AnAbstractClass: любой из его подклассов должен принимать AnInterface в качестве аргумента для method() .

Если ваш пример сработал, и у меня был другой класс BClass, реализующий AnInterface, у нас была бы ситуация, когда согласно AnAbstractClass, method() должен принимать экземпляры BClass, тогда как согласно ConcreteClass не должно.

Измените свою подпись на ConcreteClass::method, чтобы она соответствовала подписи AnAbstractClass::method.

2 голосов
/ 17 сентября 2014

Вот пример, который показывает, почему это не разрешено:

<?php
class BClass implements AnInterface { }

function moo(AnAbstractClass $abstract)
{
    $b = new BClass();
    $abstract->method($b);
}

Это будет действительный код, но он потерпит неудачу, если вы передадите moo ConcreteClass, потому что его метод ConcreteClass::method не позволяет BClass.

Это сложно, но легче понять, если вы видите пример.

2 голосов
/ 31 декабря 2010

Не вычисляется. У нас вчера была такая же дискуссия:
Могут ли типы параметров быть специализированными в PHP

Все ваши производные классы должны реализовывать сигнатуры методов одинаково.

Это то, что в идеале должно быть проверено во время выполнения. Но в PHP парсер делает. (Чтобы компенсировать это, PHP не проверяет доступ к закрытым / защищенным атрибутам во время синтаксического анализа, но допускает его взлёт во время выполнения.)

Если вы хотите применить более строгий тип, я бы посоветовал:

 assert( is_a($Object, "AClass") );
...