A child class overriding a method had to declare exactly the parent’s return type, so a factory interface could not promise that each implementation returns its own concrete type.
abstract class Repository
{
abstract public function find(int $id): Entity;
}
final class Orders extends Repository
{
// 7.4: narrower return type is allowed
public function find(int $id): Order { /* ... */ }
}
// and contravariant parameters, the mirror image:
// a child may accept a WIDER type than the parent declared
The callers of Orders::find now get an Order rather than an Entity, so the downcast and its accompanying instanceof disappear from every call site — and the static analyser can see it, which is where most of the value is. The rule is substitutability: a child may return something more specific and accept something more general, never the reverse. Interfaces get the same treatment, which is what makes a self-typed factory expressible at last.