Set type of %s::$%s must be supertype of %s (as in %s %s)

Description

A property hooked with a set hook can accept a wider range of values than its declared (get) type, since the set hook is free to convert or narrow whatever it receives before storing it. In the example, I::$prop accepts both int and string on write, even though it only ever reads back as string.

When a class overrides such a property, whether by extending a parent class or implementing an interface, the type accepted on write by the new declaration must remain a supertype of (or equal to) the type accepted by the original declaration. It must not be narrowed.

In the example, C::$prop is a plain property, so it can only be assigned values of its own declared type, string. This is narrower than the int|string accepted by I::$prop’s set hook, so code that relied on I’s contract to pass an int to $prop would break. Consequently, PHP rejects the composition.

Example

<?php

interface I {
    public string $prop {
        set(int|string $value);
    }
}

class C implements I {
    public string $prop;
}

?>

Literal Examples

  • Set type of C::$prop must be supertype of string|int (as in interface I)

Solutions

  • Give the child property (or its set hook parameter) a type that is the same as, or a supertype of, the type accepted by the parent’s set hook.

  • Add an explicit set hook to the child property, accepting the same or a wider type than the parent.

  • Narrow the type accepted by the parent’s set hook instead, if the wider type is not actually needed.

Changed Behavior

This error may appear following an evolution in behavior, in previous versions. See ` <https://php-changed-behaviors.readthedocs.io/en/latest/behavior/.html>`_.