Ковариация и контравариантность — это концепции, связанные с наследованием, использование признака не является наследованием.
Примечание. Приведенное выше утверждение не совсем верно, я объясню почему в конце этого ответа.
Из документации по PHP.
Черта аналогична классу, но предназначена только для группировки функций в мелкозернистой и согласованной форме. Невозможно создать экземпляр черты сам по себе. Это дополнение к традиционному наследованию, которое обеспечивает горизонтальную композицию поведения; то есть применение членов класса без необходимости наследования.
Почему вы видите эту ошибку?
Потому что int
не является супертипом всего и не является псевдотипом, представляющим любой тип (замените int
на mixed
в PHP 8 и посмотрите, что произойдет). Также расширение типа не позволяет использовать произвольный супертип (вы можно только опустить тип)
Например, допустим, вы определяете свой родительский метод следующим образом:
abstract public function parentMethod(int $param): bool;
Расширение типа позволяет вам опустить только тип данных $param
в файле ChildClass
.
Контравариантность позволяет тип параметра должен быть менее конкретным в дочернем методе, чем у его родителя
Допустим, у нас есть еще один класс с именем C
, который расширяет stdClass
, и мы определяем parentMethod для приема только объектов типа C
.
class C extends stdClass {}
abstract class ParentClass
{
abstract public function parentMethod(C $param): bool;
}
Теперь в ChildClass
, если мы реализуем parentMethod для приема объектов типа stdClass
public function parentMethod(stdClass $param): bool
{
}
Это будет работать, и никаких ошибок не будет.
Это контравариантность.
#Изменить Что касается вашего вопроса в комментариях
Почему можно ввести параметр реализованного типаж-метода в дочернем классе?
Поскольку черты копируются в класс, вы не можете применять к ним правила ООП. Вот почему вы можете переопределить метод final
в трейте.
trait Foo
{
final public function method($var)
{
return $var;
}
}
class Bar
{
use Foo;
// "Override" with no error
final public function method($var)
{
return $var;
}
}
Цель абстрактных методов в трейте – заставить демонстрирующий класс реализовать их (типы, а также модификаторы доступа могут отличаться)
Документация PHP гласит
Внимание Конкретный класс выполняет это требование, определяя конкретный метод с тем же именем; его подпись может отличаться.
Обновление, октябрь 2020 г.
Начиная с PHP 8 изменилось поведение абстрактных методов в типажах, и теперь абстрактные методы с несовпадающими сигнатурами завершатся с фатальной ошибкой и к ним будут применяться правила LSP.
Хорошо, почему?
Все это изменение началось с отчета об ошибке, и было некоторое обсуждение здесь
Кажется, что до PHP 8 был какой-то конфликт в поведении:
А также потому, что abstract
само по себе указывает на контракт, поэтому то, о чем вы спрашивали, является законным, и теперь с PHP 8 вы будете счастливы https://3v4l.org/7sid7 :).
person
Rain
schedule
02.01.2020