[php-src] Issue #11489: Allow optional promoted class properties to come before required
| From: | syranide | Date: | Tue, 20 Jun 2023 08:45:19 +0000 |
| Subject: | [php-src] Issue #11489: Allow optional promoted class properties to come before required | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-244754@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/11489
Author: syranide
### Description
For normal functions and classes, it largely makes sense to disallow putting optional parameters
in-front of required ones. PHP now support named arguments, which means it wouldn't be entirely
nonsensical to allow optional parameters in any order, but the use-case seems extremely niche and it
seems PHP has explicitly chosen to not support this.
```php
// Emits "Deprecated: Optional parameter $a declared before required parameter $b is implicitly
treated as a required parameter"
function f(string $a = "x", $b) {}
```
However, promoted class parameters/properties seems to intentionally diverge a bit from the normal
parameter behaviors (see #11488), at least in-terms of legacy behavior.
```php
// Valid
class PersonA {
public string|null $name = null,
public string $email,
}
```php
// Not valid (want this to be valid)
class PersonB {
public function __construct(
public string|null $name = null,
public string $email,
) {}
}
PersonA is a completely valid way to specify a class, with the optional property
in-front of the required one, and one could argue there is value in manual explicit ordering of
properties in this way. However, when using the constructor syntax with promoted parameters (e.g.
public in-front of the parameter), this is no longer allowed and optional parameters
must come last. Which makes sense when the constructor is viewed as just another function/method.
However, defining plain classes in this way (PersonB) is very useful to emulate the
benefits of plain structs due to the support for named arguments, while also guaranteeing that there
can be no partial objects of the type (which non-constructor classes fundamentally have to allow).
So you get immediate errors if you forget an argument, rather than at some point later when the
corresponding property is attempted to be accessed. Using such plain classes/structs explicitly with
named arguments makes sense in a lot of cases for representing data, because the ordering of the
parameters isn't very informative and/or there may be changes to the property list over time
which makes it very fragile to rely on order.
My feature request is that the enforced required-optional ordering is ignored for class constructor
parameters that are promoted to properties, so that PersonB above is allowed as an
alternative to PersonA, such that we can get the benefits of the constructor for
validation and named parameters, without being subject to the forced limitations that apply to
parameter ordering of normal functions.
Preferably I would want actual "struct" support, but this seems like a very close
approximation for virtually no cost and negative side-effects. Or if you feel that there are
unacceptable side-effects of this, maybe there could be an attribute that is used to explicitly
disable it instead?