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

В PHP типы параметров и возвращаемых значений могут быть изменены в дочерних классах относительно родительских. Это известно как ковариантность и контравариантность.

  • Ковариантность — «сужает» тип — позволяет использовать более конкретный тип, чем тот, который определен в родительском классе — уточняет тип возвращаемого значения.
  • Контравариантность — «расширять» тип — наоборот, позволяет использовать более общий тип. Снижает требования для входных параметров.

Давайте рассмотрим коваринтность и контравариантность на примере PHP кода.

Ковариантность

Ковариантность — это концепция в типизации языка программирования, связанная с подстановкой типов в иерархии наследования. Она позволяет использовать более конкретный тип (подтип) вместо более общего (супертипа).

Пример ковариантности

Предположим, у нас есть два класса: Animal и Cat, где Cat является подклассом Animal. У обоих есть метода get(), возвращаемый тип в Animal объявленный как Animal, мы можем использовать Cat в дочернем классе Cat, поскольку Cat является подтипом Animal .

Это допустимо, потому что Cat является подтипом Animal (т.е., Cat является Animal), поэтому это является примером ковариантности.

class Animal {
    public function get(): Animal {
        return $this;
    }
}

class Cat extends Animal {
    public function get(): Cat {
        return $this;
    }
}

Отметим, что в PHP 7.2.0 была добавлена частичная контравариантность путём устранения ограничений типа для параметров в дочернем методе.
Начиная с PHP 7.4.0, добавлена полная поддержка ковариантности и контравариантности.

Объявление типа считается конкретным в следующем случае

Удалено объединение типов.

class Base
{
	public function getNumber(): int|float|string {
		//....
	}
}

class Child extends Base {
	public function getNumber(): int|float {
		//....
	}
}

Добавлено пересечение типов

Iterator -> Iterator&Countable

Тип класса изменяется на тип дочернего класса

class Animal {
    public function get(): Animal {
        return $this;
    }
}

class Cat extends Animal {
    public function get(): Cat {
        return $this;
    }
}

iterable изменён на массив (array) или Traversable

Что такое коваринтность и контравариантность в PHP
Имеется ввиду на более узкий тип.

В противном случае класс типа считается менее конкретным.

Преимущества

Ковариантность в типизации позволяет сделать код более гибким и удобочитаемым, предоставляя преимущества, которые способствуют лучшей модульности и скорости разработки:

  1. Интуитивно понятные иерархии наследования: Когда дочерний класс может возвращать тип, являющийся подтипом типа, возвращаемого его родительским классом, иерархии наследования становятся более естественными и интуитивно понятными.
  2. Большая гибкость: Ковариантность даёт возможность более точного указания возвращаемого типа в дочерних классах, что позволяет более гибко управлять кодом.
  3. Лучшая поддержка полиморфизма: Возможность заменять типы применяется при использовании принципа подстановки Лискова (LSP), который является ключевым принципом в ООП. Это означает, что дочерний класс должен иметь возможность заменить родительский класс без изменения корректности программы.
  4. Улучшение безопасности типов: Вы получаете преимущества статической типизации, что упрощает чтение и понимание кода, а также помогает избежать определенных ошибок.
  5. Упрощение рефакторинга кода: Использование ковариантности может сделать процесс рефакторинга более безопасным и менее подверженным ошибкам, поскольку вам не нужно беспокоиться о нарушении иерархии наследования при изменении типа возвращаемого значения.

Контравариантность

Полезные ссылки


Андрей Писаревский

Автор: Андрей Писаревский 

PHP | WordPress Team Lead. Имею коммерческий опыт в программировании с 2010 года и экспертизу в полном цикле веб разработки: Frontend, Backend, QA, Server administration, управление крупными командами и Enterprise проектами.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *