A readonly class is readonly on every property

Writing readonly on every property of a value object was the only way to say something the class as a whole was trying to say.

// 8.1
final class Money
{
    public function __construct(
        public readonly int $cents,
        public readonly string $currency,
    ) {}
}

// 8.2
final readonly class Money
{
    public function __construct(
        public int $cents,
        public string $currency,
    ) {}
}

The class modifier applies to every declared property and to every property declared by a child class, which is the part worth noticing — it is inherited downwards rather than being a shorthand applied at declaration. Static properties are excluded entirely, so a readonly class may still have mutable static state, which is a gap somebody will find. It composes with final and the two mean different things: final stops extension and readonly constrains it.