Re: [RFC] Primary Constructors
| From: | Tim Düsterhus | Date: | Mon, 29 Jun 2026 20:34:17 +0000 |
| Subject: | Re: [RFC] Primary Constructors | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-131624@lists.php.net to get a copy of this message | ||
Hi
Am 2026-06-29 22:22, schrieb Rob Landers:
This was an oversight. I'll add the logic there. This is how they work: 1. Attributes on promoted primary-constructor params are reflected on both (just like promoted properties): 1. ReflectionParameter 2. ReflectionProperty 2. Attributes on bare params remain parameter-only. 3. Target validation is context-sensitive, matching existing constructor promotion behavior: 1.Thank you for confirming my assumption that expectations likely differ (https://news-web.php.net/php.internals/131610). I would expect #[Attr] to be applied to both#[ParamAttr] public int $xappears on the property too, but newInstance() from ReflectionProperty errors. 2.#[PropAttr] public int $xappears on the parameter too, but newInstance() from ReflectionParameter errors. 4. Attributes before a class remain class attributes and are not copied to the synthesized constructor. The last one is debatable, but from what I can tell from grepping, putting attributes on constructors is a very rare thing (39 out of 56,546 constructors). However, class-level attributes are a more common thing. That being said, I'd be open to changing (4) to behave like properties/parameters where it gets attached to the class and the constructor.
Foo and Foo::__construct() for consistency with promoted properties, since “Primary constructors” are effectively “Promoted Constructors”:
#[Attr]
class Foo(public int $x) { }
The error on the newInstance() will only be an issue for code that tries to unconditionally instantiate unknown attributes, which is bound to fail already since attributes do not need to be backed by a class - and arguably doing so is not super useful, since you don't know the semantics of unknown attributes. Code that knows what a given attribute means will not try to find it on mismatching targets and thus will not try to instantiate them either.
Best regards
Tim Düsterhus