PHP quiz #6 - covariance
June 16, 2019A complete guide to covariance and contravariance in PHP 7.1.
Question
Will this code throw a warning (PHP 7.1)?
- A Yes
-
B
No
Answer
Show the answerThere are a few cases where functions can be overridden with certain signatures.
Iterable
iterable
is a pseudo-type introduced in PHP 7.1.
It's like an abstract base class for variables that can be iterated with foreach (arrays, Traversable objects).
Variance (recap)
When a subclass overrides a method of a superclass, it is possible to change its parameter and return types.
Covariance | Contravariance | Invariance |
---|---|---|
Covariance
Covariance means overriding methods can return more specific types.
An array
is more specific than an iterable
.
Note that this is type safe. I like to think about the following pseudocode to justify why it works:
Polymorphism allows us to use a subclass's (ClassB) instance anywhere where a superclass's (ClassA) instance is expected. When a subclass overrides a method, it must respect the type constraints set by its parent.
In other words, the overriding method must return an iterable. Since an array is an iterable, this requirement is satisfied.
Contravariance
Contravariance means overriding methods can accept less specific parameters.
An iterable
is less specific than an array
.
This is type safe too. It's a bit harder to reason about, but here's my try:
Polymorphism allows us to use a subclass's (ClassB) instance anywhere where a superclass's (ClassA) instance is expected. When a subclass overrides a method, it must respect the type constraints set by its parent.
In this case, the overriding method must be able to receive an array type parameter. Accepting all iterables (including arrays) satisfies this requirement.
Invariance
Invariance means the overriding method cannot change the types.
Covariance, contravariance and PHP
PHP does not support covariance/contravariance. It's an invariant language. However, as always, there are a few exceptions:
1. iterable
By now it shouldn't come as a surprise that iterable
is indeed covariant/contravariant.
2. parameter type widening
From PHP 7.2 you can omit parameter types in overriding methods. This is an example of contravariance.
3. return types
If the parent method doesn’t have a return type, it can be specified. This is an example of covariance.
The future
PHP is mostly invariant, for now. But there is progress!
PHP 7.4 is going to add support for real covariance/contravariance (rfc). It will be a great improvement to PHP's type system.
This post is part of a series based on a presentation I gave on March 20, 2019.