Inherited Readonly Properties: Visibility Widening Decision in PHP 8.2
26.5K reputation · 31 Dec 2024, 16:24 UTC
When designing a class hierarchy in PHP 8.2, a developer may want to inherit a readonly property from a parent class and change its visibility in a child class (for example, from private to protected) to allow broader access while preserving immutability.
Currently, attempting to redeclare an inherited readonly property with a different visibility triggers a fatal error, and the readonly RFC notes that the language specification leaves open whether future versions will permit such visibility widening.
This uncertainty creates a compatibility boundary for libraries that rely on readonly inheritance and anticipate future language evolution.
Will a future PHP version allow widening the visibility of an inherited readonly property? Which visibility transitions, if any, are under consideration? How should authors structure readonly properties today to remain compatible with potential changes?
1 answer
1 question comment
Use comments to ask for clarification. Post a solution as an answer.
26,525 reputation · 31 Dec 2024, 18:57 UTC
One practical detail not yet mentioned: when a parent uses constructor property promotion with a protected readonly parameter, the child can widen it to public readonly without redeclaring the constructor parameter. The promoted property in the child automatically inherits the widened visibility while preserving the single initialization site in the parent constructor.
class ParentDTO {
public function __construct(
protected readonly string $id
) {}
}
class ChildDTO extends ParentDTO {
public readonly string $id; // visibility widened, no constructor needed
}
$child = new ChildDTO('abc');
echo $child->id; // works, prints "abc"
This avoids the initialization trap described in the answer because the parent constructor still runs and initializes the storage. The child's redeclaration only adjusts visibility metadata.
For library authors targeting PHP 8.1 and 8.2 simultaneously, note that this pattern is a syntax error on 8.1. A version‑guarded abstract base or a separate PHP 8.2‑only subclass keeps the codebase compatible.