# RFC: Readonly classes

- Status: Implemented (PHP 8.2)
- Authors: Máté Kocsis kocsismate@php.net
- Date: 2021-08-04
- Target: PHP 8.2
- Implementation: https://github.com/php/php-src/pull/7305
- Original: https://wiki.php.net/rfc/readonly_classes
- Page: https://externals.io/rfc/readonly_classes
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Votes

### Add readonly classes as proposed? (closed)

Yes: 28 · No: 7

Voters: asgrim (Yes), ashnazg (Yes), beberlei (Yes), bukka (Yes), bwoebi (No), crell (Yes), cschneid (No), derick (Yes), didou (Yes), diegopires (Yes), dmitry (No), dragoonis (Yes), galvao (Yes), geekcom (Yes), girgias (Yes), jbnahan (Yes), jhdxr (No), kocsismate (Yes), lcobucci (Yes), lstrojny (Yes), lufei (Yes), mauricio (Yes), mgocobachi (Yes), nicolasgrekas (Yes), ocramius (Yes), pierrick (Yes), pollita (No), reywob (No), santiagolizardo (Yes), sebastian (Yes), sergey (Yes), stas (No), theodorejb (Yes), weierophinney (Yes), wyrihaximus (Yes)

## Discussions on the mailing list

- [\[RFC\] \[Discussion\] Readonly Classes](https://externals.io/message/116472.md) — started on 2021-11-22, 9 messages
- [\[RFC\] \[Vote\] Readonly classes](https://externals.io/message/117633.md) — started on 2022-04-27, 2 messages

---

## Introduction

PHP 8.1 added support for readonly properties via [PHP RFC: Readonly properties 2.0](https://externals.io/rfc/readonly_properties_v2). However, it's still not easy to declare (quasi-)immutable classes, especially if they contain many properties. Therefore, this RFC proposes to add support for `readonly` classes.

## Proposal

The usage of the `readonly` modifier added by [PHP RFC: Readonly properties 2.0](https://externals.io/rfc/readonly_properties_v2) is extended to classes:

```php
readonly class Test {
    public string $prop;
}
```

Doing so will implicitly mark all instance properties of a class as readonly. Furthermore, it will prevent the creation of dynamic properties.

```php
readonly class Foo
{
    public int $bar;
 
    public function __construct() {
        $this->bar = 1;
    }
}
 
$foo = new Foo();
$foo->bar = 2;
// Fatal Error: Uncaught Error: Cannot modify readonly property Foo::$bar
 
$foo->baz = 1;
// Fatal Error: Uncaught Error: Cannot create dynamic property Foo::$baz
```

[PHP RFC: Deprecate dynamic properties](https://externals.io/rfc/deprecate_dynamic_properties) added support for the `#[AllowDynamicProperties]` attribute which makes it possible to create dynamic properties without triggering errors. In order not to violate the read-only constraint, marking readonly classes with the above attribute is a compile-time error:

```php
#[AllowDynamicProperties]
readonly class Foo {
}
 
// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
```

### Restrictions

As neither untyped, nor static properties are covered by the [Readonly properties RFC](https://externals.io/rfc/readonly_properties_v2#restrictions), readonly classes cannot declare them either:

```php
readonly class Foo
{
    public $bar;
}
 
// Fatal error: Readonly property Foo::$bar must have type
```

```php
readonly class Foo
{
    public static int $bar;
}
 
// Fatal error: Readonly class Foo cannot declare static properties
```

### Inheritance

Similarly how overriding of readonly properties works, a readonly class can only extend a readonly parent:

```php
readonly class A {}
readonly class B extends A {} // valid
```

But both of the following are illegal:

```php
readonly class A {}
class B extends A {}
// Fatal error: Non-readonly class B cannot extend readonly class A
```

```php
class A {}
readonly class B extends A {}
// Fatal error: Readonly class B cannot extend non-readonly class A
```

### Reflection

A `ReflectionClass::isReadOnly()` method is added, which reports whether a class is declared as read-only. Additionally, `ReflectionClass::getModifiers()` will also include the `ReflectionClass::IS_READONLY` flag.

## Backward Incompatible Changes

None.

## Errata

- <https://github.com/php/php-src/issues/9285>: It used to be possible to add non-readonly properties to readonly classes via traits. As on PHP 8.2 RC 1, traits cannot be used by readonly classes if they define any non-readonly property, otherwise a compilation error is emitted.

## Vote

Voted started on 2022-04-27, ending on 2022-05-11

**Vote: Add readonly classes as proposed?** — Yes: 28 · No: 7 (closed)
