> Le 22 janv. 2026 à 16:33, Nicolas Grekas <[email protected]> a
> écrit :
>
> Dear all,
>
> Here is a new RFC for you to consider:
> https://wiki.php.net/rfc/promoted_readonly_constructor_reassign
>
> As a quick intro, my motivation for that RFC is that I find it quite annoying
> that readonly properties play badly with CPP (constructor property promotion).
>
> Doing simple processing of any argument before assigning it to a readonly
> property forces opting out of CPP.
>
> This RFC would allow setting once a readonly property in the body of a
> constructor after the property was previously (and implicitly) set using CPP.
>
> This allows keeping property declarations in their compact form while still
> enabling validation, normalization, or conditional initialization.
>
> Cheers,
> Nicolas
Hi,
I am reserved about the proposal, because this style of using CPP and
processing the value after the fact tends to favour brevity at the expense of
precision and clarity. Let’s illustrate that with two examples from the RFC.
First:
```php
class Config {
public function __construct(
public readonly ?string $cacheDir = null,
) {
$this->cacheDir ??= sys_get_temp_dir() . '/app_cache';
}
}
```
As of today you can write:
```php
class Config {
public readonly string $cacheDir;
public function __construct(
?string $cacheDir = null,
) {
$this->cacheDir = $cacheDir ??= sys_get_temp_dir() . '/app_cache';
}
}
```
Note that the property is marked as non-nullable, a precision that may be
useful for both programmers and static analysers. With your proposal, there is
no way to keep this information.
The second example is similar:
```php
class User {
public function __construct(
public readonly string $email,
) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
$this->email = strtolower($email); // Normalize
}
}
```
As of today, it can be written as:
```php
class User {
/** @var non-empty-string & lowercase-string */
public readonly string $email;
public function __construct(
string $email,
) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
$this->email = strtolower($email); // Normalize
}
}
```
With your proposal, there is no obvious way to keep the additional information
provided in the phpdoc. Maybe we could imagine something like that:
```php
class User {
/**
* @param string $email the e-mail address as provided
*/
public function __construct(
/** @var non-empty-string & lowercase-string the normalised e-mail
address */
string $email,
) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
$this->email = strtolower($email); // Normalize
}
}
```
but it is obviously clearer (at least to my eyes) to keep the property and the
constructor parameter separate.
One additional thought: Readonly properties carry a constraint that is annoying
at first, but that is finally beneficial for the clarity of code that is
written. When initialising such a property with something more complex than
what can be comfortably written in a single expression, I am forced to write
the intermediate results in a temporary variable and to assign the final value
to the property at the end of the process, instead of transforming gradually
the value of the property. The resulting code is a few lines longer, but it is
no less clear, even it is often clearer, because it is obvious that this
specific assignment supplies the final value of the property, and there is no
need to look further down to see whether the value will undergo some additional
transformations. As of today, this “final assignment” may be part of the
constructor signature; with this RFC implemented, one can no longer know at a
glance whether this assignment is “final”.
(Also I sympathise with Larry: rigid coding styles and static analysers’
promoted “good practices” add problematic limitations that are not part of the
semantics of language. I prefer disabling checks in PHPStan rather than
downgrading to non-safe mutable properties and/or writing getters around them.)
—Claude