Starting with PHP 7.4, you can specify covariant return types in your class methods. This means that the return type of methods can be narrowed (i.e. made more specific) when overriding the return type of the parent method.
In PHP, a type declaration is considered more specific when you:
- Remove a type from a union type;
- Adding a type to an intersection type;
- Change a class type to a subtype;
- Change
iterable
toarray
orTraversable
; - Narrow an untyped type to be typed.
Please note the following:
- It is type safe to allow an overriding method to return a more specific type than the method in the base class;
- PHP does not support covariance for the
callable
return type; - PHP allows covariance in method parameters in class constructors;
- Covariance rules also work on return types specified in
interface
methods.
Removing a Type From a Union Type
If, from the overriding child method's return type, you remove a type from a union type, it makes the return type more specific. For example:
// PHP 8+
class A
{
public function foo(): string|int|float
{
// ...
}
}
class B extends A
{
public function foo(): string|int
{
// ...
}
}
Adding a Type to an Intersection Type
If, to the overriding child method's return type, you add a type to an intersection type, it makes the return type more specific. For example:
// PHP 8.1+
class A
{
public function foo(): Bar
{
// ...
}
}
class B extends A
{
public function foo(): Bar&Qux
{
// ...
}
}
Changing a Class Type to a Subtype
When overriding the parent method's return type, the child class can specify a subtype of the class type specified as the parent method's return type. For example:
// PHP 7.4+
class A
{
public function foo(): object
{
// ...
}
}
class B extends A
{
public function foo(): stdClass
{
// ...
}
}
In the example above you can see how the B::foo()
method specifies a more specific return type than its parent, of type stdClass
(which is a subtype of object
).
Changing iterable
to array
or Traversable
iterable
return types can be narrowed by specifying array
or the Traversable
interface as return types. For example:
// PHP 7.4+
class A
{
public function foo(): iterable
{
// ...
}
}
class B extends A
{
public function foo(): array
{
// ...
}
}
// PHP 7.4+
class A
{
public function foo(): iterable
{
// ...
}
}
class B extends A
{
public function foo(): Traversable
{
// ...
}
}
Narrowing an Untyped Type to be Typed
When a method has no return type specified (i.e. it is untyped), then any return type you specify in the child method (when overriding) would make it more specific. For example:
// PHP 7.4+
class A
{
public function foo()
{
// ...
}
}
class B extends A
{
public function foo(): string
{
// ...
}
}
This post was published (and was last revised ) by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.