rfc:constructor_promotion
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
rfc:constructor_promotion [2020/04/02 10:02] – nikic | rfc:constructor_promotion [2020/05/15 12:14] – Fix a couple typos theodorejb | ||
---|---|---|---|
Line 2: | Line 2: | ||
* Date: 2020-03-26 | * Date: 2020-03-26 | ||
* Author: Nikita Popov < | * Author: Nikita Popov < | ||
- | * Status: | + | * Status: |
* Target Version: PHP 8.0 | * Target Version: PHP 8.0 | ||
* Implementation: | * Implementation: | ||
Line 19: | Line 19: | ||
float $x = 0.0, | float $x = 0.0, | ||
float $y = 0.0, | float $y = 0.0, | ||
- | float $z = 0.0 | + | float $z = 0.0, |
) { | ) { | ||
$this->x = $x; | $this->x = $x; | ||
Line 39: | Line 39: | ||
public float $x = 0.0, | public float $x = 0.0, | ||
public float $y = 0.0, | public float $y = 0.0, | ||
- | public float $z = 0.0 | + | public float $z = 0.0, |
) {} | ) {} | ||
} | } | ||
Line 60: | Line 60: | ||
abstract class Test { | abstract class Test { | ||
// Error: Abstract constructor. | // Error: Abstract constructor. | ||
- | abstract public function __construct(private $x) {} | + | abstract public function __construct(private $x); |
} | } | ||
interface Test { | interface Test { | ||
// Error: Abstract constructor. | // Error: Abstract constructor. | ||
- | public function __construct(private $x) {} | + | public function __construct(private $x); |
} | } | ||
</ | </ | ||
While unusual, promoted parameters may occur inside trait constructors. | While unusual, promoted parameters may occur inside trait constructors. | ||
+ | |||
+ | Promoted properties have to be prefixed by one of the visibility keywords, use of '' | ||
+ | |||
+ | <PHP> | ||
+ | class Test { | ||
+ | // Error: " | ||
+ | public function __construct(var $prop) {} | ||
+ | } | ||
+ | </ | ||
Properties declared through promoted parameters are subject to the same restrictions as normal property declarations. In particular, it is not possible to declare the same property twice: | Properties declared through promoted parameters are subject to the same restrictions as normal property declarations. In particular, it is not possible to declare the same property twice: | ||
Line 82: | Line 91: | ||
</ | </ | ||
- | It is also not possible to use the '' | + | It is also not possible to use the '' |
<PHP> | <PHP> | ||
Line 151: | Line 160: | ||
While repeating the default value on the property declaration would currently appear harmless, there are forward-compatibility reasons why it is preferable to only specify the default once. | While repeating the default value on the property declaration would currently appear harmless, there are forward-compatibility reasons why it is preferable to only specify the default once. | ||
- | The first is a possible future extension to allow arbitrary | + | The first is a possible future extension to allow arbitrary |
<PHP> | <PHP> | ||
Line 213: | Line 222: | ||
==== Reflection ==== | ==== Reflection ==== | ||
- | Property declarations promoted from a constructor are available through reflection | + | Reflection |
While PHP does not expose doc comments on parameters, doc comments on promoted properties will be retained: | While PHP does not expose doc comments on parameters, doc comments on promoted properties will be retained: | ||
Line 230: | Line 239: | ||
As the example indicates, this allows using doc comment based annotations with promoted properties. | As the example indicates, this allows using doc comment based annotations with promoted properties. | ||
+ | |||
+ | Additionally, | ||
+ | |||
+ | * '' | ||
+ | * '' | ||
+ | |||
+ | Most reflection code should not care whether properties are generated or not, but this information will allow reconstructing the structure or the original code more easily. | ||
+ | |||
+ | ==== Inheritance ==== | ||
+ | |||
+ | Constructor promotion can be used in conjunction with inheritance, | ||
+ | |||
+ | <PHP> | ||
+ | abstract class Node { | ||
+ | public function __construct( | ||
+ | protected Location $startLoc = null, | ||
+ | protected Location $endLoc = null, | ||
+ | ) {} | ||
+ | } | ||
+ | |||
+ | class ParamNode extends Node { | ||
+ | public function __construct( | ||
+ | public string $name, | ||
+ | public ExprNode $default = null, | ||
+ | public TypeNode $type = null, | ||
+ | public bool $byRef = false, | ||
+ | public bool $variadic = false, | ||
+ | Location $startLoc = null, | ||
+ | Location $endLoc = null, | ||
+ | ) { | ||
+ | parent:: | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The '' | ||
+ | |||
+ | <PHP> | ||
+ | abstract class Node { | ||
+ | protected Location $startLoc; | ||
+ | protected Location $endLoc; | ||
+ | |||
+ | public function __construct( | ||
+ | Location $startLoc = null, | ||
+ | Location $endLoc = null, | ||
+ | ) { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class ParamNode extends Node { | ||
+ | public string $name; | ||
+ | public ExprNode $default; | ||
+ | public TypeNode $type; | ||
+ | public bool $byRef; | ||
+ | public bool $variadic; | ||
+ | |||
+ | public function __construct( | ||
+ | string $name, | ||
+ | ExprNode $default = null, | ||
+ | TypeNode $type = null, | ||
+ | bool $byRef = false, | ||
+ | bool $variadic = false, | ||
+ | Location $startLoc = null, | ||
+ | Location $endLoc = null, | ||
+ | ) { | ||
+ | $this-> | ||
+ | $this-> | ||
+ | $this-> | ||
+ | $this-> | ||
+ | $this-> | ||
+ | parent:: | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | It should be noted that the property assignments happen before the parent constructor is invoked. This is unusual in terms of coding style, but should not impact behavior for non-degenerate cases. | ||
+ | |||
+ | ==== Attributes ==== | ||
+ | |||
+ | As PHP 8 also introduces [[rfc: | ||
+ | |||
+ | <PHP> | ||
+ | class Test { | ||
+ | public function __construct( | ||
+ | << | ||
+ | public int $prop, | ||
+ | ) {} | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | This code could desugar in one of four ways: | ||
+ | |||
+ | - The attribute is applied only to the parameter. | ||
+ | - The attribute is applied only to the implied property. | ||
+ | - The attribute is applied both to the parameter and the property. | ||
+ | - Attributes on promoted properties are forbidden, due to ambiguity. | ||
+ | |||
+ | Here are the possible transformations: | ||
+ | |||
+ | <PHP> | ||
+ | // Option 1: Attribute applies only to parameter. | ||
+ | class Test { | ||
+ | public int $prop; | ||
+ | | ||
+ | public function __construct( | ||
+ | << | ||
+ | int $prop, | ||
+ | ) {} | ||
+ | } | ||
+ | |||
+ | // Option 2: Attribute applies only to property. | ||
+ | class Test { | ||
+ | << | ||
+ | public int $prop; | ||
+ | | ||
+ | public function __construct( | ||
+ | int $prop, | ||
+ | ) {} | ||
+ | } | ||
+ | |||
+ | // Option 3: Attribute applies to both | ||
+ | class Test { | ||
+ | << | ||
+ | public int $prop; | ||
+ | | ||
+ | public function __construct( | ||
+ | << | ||
+ | int $prop, | ||
+ | ) {} | ||
+ | } | ||
+ | |||
+ | // Option 4: Error, cannot use attributes with constructor parameter promotion. | ||
+ | </ | ||
+ | |||
+ | This RFC proposes to use option 3 (applying the attribute to both property and parameter), as it is the most flexible. The '' | ||
+ | |||
+ | However, I consider this to be something of an implementation detail. If further work on attributes prior to the PHP 8 release shows that it would be advantageous to place the attribute only on the property, we should be open to such a change. | ||
==== Coding Style Considerations ==== | ==== Coding Style Considerations ==== | ||
Line 252: | Line 400: | ||
public float $x = 0.0, | public float $x = 0.0, | ||
public float $y = 0.0, | public float $y = 0.0, | ||
- | public float $z = 0.0 | + | public float $z = 0.0, |
) {} | ) {} | ||
} | } | ||
Line 283: | Line 431: | ||
float $x = 0.0, | float $x = 0.0, | ||
float $y = 0.0, | float $y = 0.0, | ||
- | float $z = 0.0 | + | float $z = 0.0, |
) { | ) { | ||
$this->x = $x; | $this->x = $x; | ||
Line 301: | Line 449: | ||
Larry provided some broader vision on how this feature can be combined with other features to improve our object initialization story in https:// | Larry provided some broader vision on how this feature can be combined with other features to improve our object initialization story in https:// | ||
- | |||
- | Because constructor signatures that include promoted properties are likely to become long enough to require line-breaks, | ||
- | |||
- | <PHP> | ||
- | class Point { | ||
- | public function __construct( | ||
- | public float $x = 0.0, | ||
- | public float $y = 0.0, | ||
- | public float $z = 0.0, // <-- Allow this comma. | ||
- | ) {} | ||
- | } | ||
- | </ | ||
- | |||
- | Optional trailing commas in this position were previously declined, but I believe we have a stronger case for them nowadays, especially in conjunction with this feature. | ||
===== Prior Art ===== | ===== Prior Art ===== | ||
Line 332: | Line 466: | ||
===== Vote ===== | ===== Vote ===== | ||
- | Yes/No. | + | Voting started 2020-05-15 and closes 2020-05-29. |
+ | |||
+ | <doodle title=" | ||
+ | | ||
+ | | ||
+ | </ | ||
rfc/constructor_promotion.txt · Last modified: 2020/08/01 23:38 by carusogabriel