← Назад к вопросам

Что такое контравариантность?

2.7 Senior🔥 91 комментариев
#PHP Core#ООП

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое контравариантность в PHP?

Контравариантность — это важное понятие в современных объектно-ориентированных языках программирования, включая PHP, которое описывает обратное отношение подтипов при работе с параметрами методов в контексте наследования. Она является одной из сторон ковариантности и контравариантности, которые регулируют правила подстановки типов в системе типов.

Контравариантность в контексте параметров метода

Когда класс расширяет другой класс (наследуется от него), его методы могут переопределять методы родительского класса. Контравариантность разрешает параметрам переопределённого метода иметь тип, который является родительским (более общим) по отношению к типу параметра в базовом методе.

<?php

class Animal {}
class Dog extends Animal {}

interface Speaker {
    public function speak(Animal $animal): void;
}

class ConcreteSpeaker implements Speaker {
    // Контравариантность: параметр $animal может быть БОЛЕЕ ОБЩИМ типом (Animal)
    // в базовом методе, но в реализации мы принимаем БОЛЕЕ КОНКРЕТНЫЙ тип (Dog)
    // В PHP это НЕ разрешено без явного указания контравариантности!
    public function speak(Dog $animal): void {
        echo "Говорит с собакой!\n";
    }
}

В чистом виде контравариантность параметров НЕ поддерживается в PHP для переопределения методов классов. Однако PHP поддерживает контравариантность для возвращаемых типов (ковариантность) и, с версии 7.4, для типов параметров в методах интерфейсов при использовании объединённых типов (union types) в определённых случаях.

Контравариантность в реальности PHP

С PHP 8.0 появились возможности, которые косвенно касаются контравариантности:

  1. Контравариантность для параметров в методах интерфейсов — если метод в интерфейсе имеет параметр с типом A|B, реализация может использовать только A или B (это более конкретный тип, что фактически нарушает чистую контравариантность, но показывает её идею).
<?php

interface Processor {
    public function process(int|string $data): void;
}

class IntProcessor implements Processor {
    // Мы принимаем более конкретный тип (int) вместо общего (int|string)
    // Это пример контравариантного поведения для объединённых типов
    public function process(int $data): void {
        echo "Processing int: $data\n";
    }
}
  1. Контравариантность в дженериках (обобщённых типах) — в языках с поддержкой дженериков (например, Java, C#) контравариантность часто используется для коллекций. В PHP дженерики отсутствуют, но аналоги можно найти в типизированных массивах или библиотеках.

Почему контравариантность важна?

  • Безопасность типов: Контравариантность гарантирует, что метод, который ожидает более общий тип, может безопасно работать с любым подтипом через переопределение.
  • Полиморфизм: Она позволяет реализациям быть более специфичными для определённых подтипов, повышая специализацию.
  • Гибкость дизайна: В шаблонах проектирования, таких как Visitor или Strategy, контравариантность может уменьшить количество проверок типов.

Сравнение с ковариантностью

  • Ковариантность (возвращаемые типы): Подтип может возвращать более конкретный тип.
    class Base {
        public function get(): Animal { return new Animal(); }
    }
    class Derived extends Base {
        public function get(): Dog { return new Dog(); } // Ковариантность разрешена в PHP 7.4+
    }
    
  • Контравариантность (параметры): Подтип может принимать более общий тип (в PHP ограничена).

Ограничения в PHP

В PHP контравариантность параметров при переопределении методов классов запрещена из соображений безопасности типов. Если метод ожидает Dog, а переопределённый метод принимает Animal, это может привести к ошибкам, так как код может передать Cat в метод, предназначенный только для Dog.

<?php

class Base {
    public function feed(Dog $dog): void {}
}
class Derived extends Base {
    // Это вызовет ошибку в PHP!
    public function feed(Animal $animal): void {}
}

Практическое применение

Контравариантность чаще встречается в:

  • Шаблонах проектирования (например, Visitor, где методы visit могут принимать разные типы).
  • Функциях высшего порядка (callback-функции, которые могут принимать более общие аргументы).
  • Системах с дженериками (например, коллекции, где Collection<Animal> может быть присвоена Collection<Dog> при контравариантности).

В PHP, без полной поддержки дженериков, контравариантность остаётся скорее теоретическим понятием, но её понимание важно для дизайна типов и безопасного переопределения методов. Она подчёркивает принцип принципа подстановки Лисков (LSP), где подтипы должны быть заменяемыми без нарушения поведения программы.

Что такое контравариантность? | PrepBro