Skip to content

Allow optional promoted class properties to come before required #11489

@syranide

Description

@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.

// 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.

// Valid
class PersonA {
  public string|null $name = null,
  public string $email,
}
// 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?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions