A readonly property must have a type, so a readonly class containing an untyped property is a compile error rather than a silently ignored one.
readonly class Config
{
public $value; // Fatal error: Readonly property
// Config::$value must have type
}
// and the other two refusals
readonly class WithStatic
{
public static int $count = 0; // allowed, and MUTABLE
}
class NotReadonly extends SomeReadonlyClass {}
// Fatal: Non-readonly class cannot extend readonly class
The type requirement exists because readonly is implemented on top of typed properties — the uninitialised state that makes write-once possible only exists for typed properties, and an untyped one is initialised to null at construction. The static exception is the one to write down somewhere: a readonly class with a static counter is legal, mutable, and looks immutable to anybody reading the declaration.