Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread fennic log
On Mon, 29 Jun 2026 at 01:18, Rob Landers  wrote:

> Hello internals,
>
> I'd like to put forward Primary Constructors
>  for comment.
>
> An implementation PR will be opened later today (UTC), and the RFC updated
> with this discussion thread.
>
> — Rob
>

I think this would be a great addition to PHP.
There has been a few times in my career where I have needed to extend a 3rd
party library and calling `parent::__construct($params);` at the end of my
extending class always felt dirty.
Being able to use
```
class MyClass(int arg1, string $arg2) extends Base(string $arg2)
{}
```
Is much better, and clearer.
It can avoid mistakes where a developer extends a class, doesnt call the
parent constructor, it works but the base class might not be correctly
initialized and might break down the line in production.
Having an explicit "this get passed to the class we are extended" in the
definition would wipe out that headache area.


Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Rowan Tommins [IMSoP]
On 1 July 2026 12:25:53 BST, Nick Sdot  wrote:
>You cannot do the below with a hook. Having the primary constructor body 
>solves it:
>
>```
>
>final readonly class Foo(Collection|array $value) implementsBar {
>$this->items = $value instanceof Collection ? $value : new 
> Collection($value);
>}=> {
>// class body private Collection $items
>
>}
>
>```


OK, I think I get it. But a normal constructor also works just fine. You don't 
have to "remove readonly and check the whole class", you just add exactly the 
code you've added above, but move the constructor parameters from next to the 
class name to next to the word "__construct":

```
final readonly class Foo implements Bar {
public function __construct(Collection|array $value) {
   $this->items = $value instanceof Collection ? $value : new 
Collection($value);
}

private Collection $items
}
```

If we're talking about refactoring, the previous version presumably looked like 
this: 

```
final readonly class Foo(private Collection $items) implements Bar {
// ...
}
```

So whether the refactoring is "add a constructor and a property declaration" or 
"add a primary constructor body and a property declaration" doesn't make much 
difference. The readonly keyword, and the rest of the class, stay exactly the 
same.

The appeal of the primary constructor syntax to me is that it's concise and 
does everything in one go. As soon as you add an explicit body and a separate 
property declaration, you've lost the conciseness, regardless of where you put 
that body; so you might as well just use the existing syntax rather than 
inventing a new one.



Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Nick Sdot

Hey Rowan,

On 01.07.26 18:43, Rowan Tommins [IMSoP] wrote:

On 1 July 2026 09:51:00 BST, Nick Sdot wrote:

Just imagine you have to refactor an existing class with a primary constructor. 
`readonly` would prevent what you want to do and must be removed. This would 
require you to check and refactor the whole class, instead of just adding a 
body. It doesn't make sense.


I don't understand this paragraph at all. The proposed syntax doesn't change 
anything about how readonly works, as far as I know.

Any "primary constructor body" or "init block", whatever syntax it had, would 
have exactly the same abilities and limitations regarding readonly properties as a normal 
constructor. It would just be a different way of spelling it.



Rowan Tommins
[IMSoP]



Not sure how else I could explain it. What's not clear? Trying...

The limitation are property hooks in `readonly` classes. By having the 
primary constructor body with "exactly the same abilities and 
limitations regarding readonly properties as a normal constructor" you 
*can* assign the property in question in the primary constructor body. 
If there is no body, you cannot work around it. Unless, of course, you 
don't use primary constructors. Which brings me back to "new, great 
feature unusable in endless situations" -- which should not be our aim IMO.


You cannot do the below with a hook. Having the primary constructor body 
solves it:


```

final readonly class Foo(Collection|array $value) implementsBar {
$this->items = $value instanceof Collection ? $value : new 
Collection($value);
}=> {
// class body private Collection $items

}

```

I really like the general idea of this RFC, and I would like to have it. 
But without bodies it's broken in too many situations.


--

Cheers
Nick


Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Rowan Tommins [IMSoP]
On 1 July 2026 09:51:00 BST, Nick Sdot  wrote:
>
> Just imagine you have to refactor an existing class with a primary 
> constructor. `readonly` would prevent what you want to do and must be 
> removed. This would require you to check and refactor the whole class, 
> instead of just adding a body. It doesn't make sense.


I don't understand this paragraph at all. The proposed syntax doesn't change 
anything about how readonly works, as far as I know.

Any "primary constructor body" or "init block", whatever syntax it had, would 
have exactly the same abilities and limitations regarding readonly properties 
as a normal constructor. It would just be a different way of spelling it. 



Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Nick Sdot

Hey Rob,

On 01.07.26 17:43, Rob Landers wrote:

On Wed, Jul 1, 2026, at 10:51, Nick Sdot wrote:


Hey Rowan,

On 01.07.26 15:32, Rowan Tommins [IMSoP] wrote:

On 1 July 2026 04:29:48 BST, Nick Sdot 
 wrote:

```

final readonly class Dog(
string $name,
)extends Animal {
parent::__construct($name);
}=> {
// class body }

```

The above:
- does NOT have a parent constructor shortcut call -> `extends Animal`
- DOES allow parent constructor call in primary constructor body
- behaves exactly (!) as a conventional constructor; in fact syntax sugar

```

final readonly class Dog(
string $name,
)extends Animal($name)// already IS the parent constructor call... {
// hence, here no parent constructor call allowed }=> {
// class body }

```

The above:
- DOES have a parent constructor shortcut call -> `extends Animal($name)`
- does NOT allow parent constructor call in primary constructor body
- *no difference in parent constructor calling behaviour to what the RFC pr

ooposes now*
...


So where is the complexity?

So now we have to specify:

- a brand new syntax for putting a code block outside the class body
- a parser rule to detect parent conductor calls (is 
ParentClassName::__construct also forbidden? What about 
DeeperAncestor::__construct?)
- the order of operations if there's a body and a shorthand parent call
- maybe other details of how the constructor body works which I haven't thought 
of



As with the rest of the feature, to make the proposed changes work in 
the class header, yes. :)
Of course *any* parent constructor call would be forbidden from the 
body if the parent shorthand is used. The "already IS the parent... 
hence, here no parent..." gives no room for interpretation, I think.
The order could be discussed, and a default (probably after, because 
that's how it seem to work without body) be agreed on. Since there 
would be a body, manually calling the parent constructor would be 
possible if the default doesn't suit ones intend.


I still don't see an explosion of complexity.


What would justify not allowing the body that helps to address a real problem?

Many people see having more than one way to write the same thing as a cost, 
which needs to be outweighed by some benefit.

I'm on the fence whether primary constructors as they are in the current RFC 
are worthwhile; they're a tidy shorthand for a common case, but not saving that 
much over existing constructor promotion.

With your proposal to make them just a different way of writing any constructor, using a 
weird new syntax which puts code outside of the class body, I would be a definite 
"no".

That's just my opinion of the cost-benefit balance.


Bit sad to see that there is not even the will to discuss it. But 
fair, everyone can have their opinion. Then I hope the "on the fence" 
will eventually be a "no". Because there is IMO no reality where 
introducing this without bodies, and hence with no solution to the 
issues I pointed out, is easier to reason about than what I propose 
here. Just imagine you have to refactor an existing class with a 
primary constructor. `readonly` would prevent what you want to do and 
must be removed. This would require you to check and refactor the 
whole class, instead of just adding a body. It doesn't make sense.


We don't need more half finished, half not working, confusing 
features in PHP.

Rowan Tommins
[IMSoP]


--

Cheers
Nick


Hi Nick,

First of all, the fact that three people have submitted different 
syntaxes (putting aside that I also haven’t shared my preference as 
well), should be an indication that it isn’t straightforward; just 
from a “what does it look like” perspective.


It isn’t simply “just run this code”.

I would very much ask that you move this discussion to a different 
thread. As the RFC author, who rejected it as future scope, I can’t 
engage with your proposal here. All I can say is that I reject it for 
future scope, repeatedly.


Moving it outside the thread would let people in this thread discuss 
the RFC as proposed, and if there’s a consensus in the new thread, 
perhaps it could be adopted into this RFC or even proposed as an 
immediate following RFC.


Arguing for it here, cuts off my hands and is a distraction.

— Rob



As I said earlier, I disagree that this is unrelated. Calling it a 
"distraction" is... I don't know. The very feature your RFC proposes 
will create a new problem, because you hold the opinion that preexisting 
limitations could just be ignored (or moved to future scope) for a *new* 
feature. I think that is wrong, and not good for the language -- which I 
had to point out. People actively engaged with my concern in this very 
branch of the thread, I responded. That is what the list is for?  I, 
however, understand that you stick to rejecting; I will not add anything 
new and if no one else shares my concern then this branch and topic will 
naturally die down.


--

Cheers
Nick


Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Rob Landers
On Wed, Jul 1, 2026, at 10:51, Nick Sdot wrote:
> Hey Rowan,
> 
> On 01.07.26 15:32, Rowan Tommins [IMSoP] wrote:
>> On 1 July 2026 04:29:48 BST, Nick Sdot  wrote:
>>> ```
>>> 
>>> final readonly class Dog(
>>>string $name,
>>> )extends Animal {
>>>parent::__construct($name);
>>> }=> {
>>>// class body }
>>> 
>>> ```
>>> 
>>> The above:
>>> - does NOT have a parent constructor shortcut call -> `extends Animal`
>>> - DOES allow parent constructor call in primary constructor body
>>> - behaves exactly (!) as a conventional constructor; in fact syntax sugar
>>> 
>>> ```
>>> 
>>> final readonly class Dog(
>>>string $name,
>>> )extends Animal($name)// already IS the parent constructor call... {
>>>// hence, here no parent constructor call allowed }=> {
>>>// class body }
>>> 
>>> ```
>>> 
>>> The above:
>>> - DOES have a parent constructor shortcut call -> `extends Animal($name)`
>>> - does NOT allow parent constructor call in primary constructor body
>>> - *no difference in parent constructor calling behaviour to what the RFC pr
>> ooposes now*
>>> 
>> ...
>> 
>>> So where is the complexity? 
>> So now we have to specify: 
>> 
>> - a brand new syntax for putting a code block outside the class body
>> - a parser rule to detect parent conductor calls (is 
>> ParentClassName::__construct also forbidden? What about 
>> DeeperAncestor::__construct?)
>> - the order of operations if there's a body and a shorthand parent call
>> - maybe other details of how the constructor body works which I haven't 
>> thought of
>> 
> 
> As with the rest of the feature, to make the proposed changes work in the 
> class header, yes. :)
> Of course *any* parent constructor call would be forbidden from the body if 
> the parent shorthand is used. The "already IS the parent... hence, here no 
> parent..." gives no room for interpretation, I think.
> The order could be discussed, and a default (probably after, because that's 
> how it seem to work without body) be agreed on. Since there would be a body, 
> manually calling the parent constructor would be possible if the default 
> doesn't suit ones intend.
> 
> I still don't see an explosion of complexity.
> 
>> 
>>> What would justify not allowing the body that helps to address a real 
>>> problem?
>> Many people see having more than one way to write the same thing as a cost, 
>> which needs to be outweighed by some benefit.
>> 
>> I'm on the fence whether primary constructors as they are in the current RFC 
>> are worthwhile; they're a tidy shorthand for a common case, but not saving 
>> that much over existing constructor promotion.
>> 
>> With your proposal to make them just a different way of writing any 
>> constructor, using a weird new syntax which puts code outside of the class 
>> body, I would be a definite "no".
>> 
>> That's just my opinion of the cost-benefit balance.
> 
> Bit sad to see that there is not even the will to discuss it. But fair, 
> everyone can have their opinion. Then I hope the "on the fence" will 
> eventually be a "no". Because there is IMO no reality where introducing this 
> without bodies, and hence with no solution to the issues I pointed out, is 
> easier to reason about than what I propose here. Just imagine you have to 
> refactor an existing class with a primary constructor. `readonly` would 
> prevent what you want to do and must be removed. This would require you to 
> check and refactor the whole class, instead of just adding a body. It doesn't 
> make sense.
> 
> We don't need more half finished, half not working, confusing features in 
> PHP.  
>> Rowan Tommins
>> [IMSoP]
> 
> --
> 
> Cheers
> Nick

Hi Nick,

First of all, the fact that three people have submitted different syntaxes 
(putting aside that I also haven’t shared my preference as well), should be an 
indication that it isn’t straightforward; just from a “what does it look like” 
perspective. 

It isn’t simply “just run this code”.

I would very much ask that you move this discussion to a different thread. As 
the RFC author, who rejected it as future scope, I can’t engage with your 
proposal here. All I can say is that I reject it for future scope, repeatedly.

Moving it outside the thread would let people in this thread discuss the RFC as 
proposed, and if there’s a consensus in the new thread, perhaps it could be 
adopted into this RFC or even proposed as an immediate following RFC.

Arguing for it here, cuts off my hands and is a distraction.

— Rob

Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Nick Sdot

Hey Rowan,

On 01.07.26 15:32, Rowan Tommins [IMSoP] wrote:

On 1 July 2026 04:29:48 BST, Nick Sdot wrote:

```

final readonly class Dog(
string $name,
)extends Animal {
parent::__construct($name);
}=> {
// class body }

```

The above:
- does NOT have a parent constructor shortcut call -> `extends Animal`
- DOES allow parent constructor call in primary constructor body
- behaves exactly (!) as a conventional constructor; in fact syntax sugar

```

final readonly class Dog(
string $name,
)extends Animal($name)// already IS the parent constructor call... {
// hence, here no parent constructor call allowed }=> {
// class body }

```

The above:
- DOES have a parent constructor shortcut call -> `extends Animal($name)`
- does NOT allow parent constructor call in primary constructor body
- *no difference in parent constructor calling behaviour to what the RFC pr

ooposes now*
...


So where is the complexity?

So now we have to specify:

- a brand new syntax for putting a code block outside the class body
- a parser rule to detect parent conductor calls (is 
ParentClassName::__construct also forbidden? What about 
DeeperAncestor::__construct?)
- the order of operations if there's a body and a shorthand parent call
- maybe other details of how the constructor body works which I haven't thought 
of



As with the rest of the feature, to make the proposed changes work in 
the class header, yes. :)
Of course *any* parent constructor call would be forbidden from the body 
if the parent shorthand is used. The "already IS the parent... hence, 
here no parent..." gives no room for interpretation, I think.
The order could be discussed, and a default (probably after, because 
that's how it seem to work without body) be agreed on. Since there would 
be a body, manually calling the parent constructor would be possible if 
the default doesn't suit ones intend.


I still don't see an explosion of complexity.


What would justify not allowing the body that helps to address a real problem?

Many people see having more than one way to write the same thing as a cost, 
which needs to be outweighed by some benefit.

I'm on the fence whether primary constructors as they are in the current RFC 
are worthwhile; they're a tidy shorthand for a common case, but not saving that 
much over existing constructor promotion.

With your proposal to make them just a different way of writing any constructor, using a 
weird new syntax which puts code outside of the class body, I would be a definite 
"no".

That's just my opinion of the cost-benefit balance.


Bit sad to see that there is not even the will to discuss it. But fair, 
everyone can have their opinion. Then I hope the "on the fence" will 
eventually be a "no". Because there is IMO no reality where introducing 
this without bodies, and hence with no solution to the issues I pointed 
out, is easier to reason about than what I propose here. Just imagine 
you have to refactor an existing class with a primary constructor. 
`readonly` would prevent what you want to do and must be removed. This 
would require you to check and refactor the whole class, instead of just 
adding a body. It doesn't make sense.


We don't need more half finished, half not working, confusing features 
in PHP.

Rowan Tommins
[IMSoP]


--

Cheers
Nick

Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Tim Düsterhus

Hi

Am 2026-06-29 21:07, schrieb Tim Düsterhus:

Am 2026-06-29 02:17, schrieb Rob Landers:
I'd like to put forward Primary Constructors 
 for comment.


The RFC currently does not specify the interaction with visibility. It 
is currently implied that the constructor will be `public`, but the RFC 
doesn't spell that out and doesn't specify whether or not it is 
possible to make such a constructor non-public (e.g. to actually treat 
it as a “primary constructor” in a sea of multiple named constructors).


The RFC also doesn't specify whether the parent constructor call 
supports named arguments:


class P(public string $foo, public string $bar) { }

class C(string $bar, string $foo) extends P(bar: $bar, foo: $foo) { 
}


Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] Primary Constructors

2026-07-01 Thread Rowan Tommins [IMSoP]
On 1 July 2026 04:29:48 BST, Nick Sdot  wrote:
>
>```
>
>final readonly class Dog(
>string $name,
>)extends Animal {
>parent::__construct($name);
>}=> {
>// class body }
>
>```
>
>The above:
>- does NOT have a parent constructor shortcut call -> `extends Animal`
>- DOES allow parent constructor call in primary constructor body
>- behaves exactly (!) as a conventional constructor; in fact syntax sugar
>
>```
>
>final readonly class Dog(
>string $name,
>)extends Animal($name)// already IS the parent constructor call... {
>// hence, here no parent constructor call allowed }=> {
>// class body }
>
>```
>
>The above:
>- DOES have a parent constructor shortcut call -> `extends Animal($name)`
>- does NOT allow parent constructor call in primary constructor body
>- *no difference in parent constructor calling behaviour to what the RFC pr
ooposes now*
>
...

> So where is the complexity? 

So now we have to specify: 

- a brand new syntax for putting a code block outside the class body
- a parser rule to detect parent conductor calls (is 
ParentClassName::__construct also forbidden? What about 
DeeperAncestor::__construct?)
- the order of operations if there's a body and a shorthand parent call
- maybe other details of how the constructor body works which I haven't thought 
of


> What would justify not allowing the body that helps to address a real problem?

Many people see having more than one way to write the same thing as a cost, 
which needs to be outweighed by some benefit.

I'm on the fence whether primary constructors as they are in the current RFC 
are worthwhile; they're a tidy shorthand for a common case, but not saving that 
much over existing constructor promotion.

With your proposal to make them just a different way of writing any 
constructor, using a weird new syntax which puts code outside of the class 
body, I would be a definite "no".

That's just my opinion of the cost-benefit balance.



Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-30 Thread Nick Sdot


On 30.06.26 23:55, Larry Garfield wrote:

On Mon, Jun 29, 2026, at 3:56 PM, Nick Sdot wrote:


     final readonly class Foo(Collection|array $value) implements Bar {
     $this->items = $value instanceof Collection ? $value : new
Collection($value);
     } => {
     public Collection $items;

     // class body private Collection $items
     }

     final readonly class Foo implements Bar {
     public Collection $items;

     public function __construct(Collection|array $value) {
     $this->items = $value instanceof Collection ? $value : new
Collection($value);
     }

     // class body private Collection $items
     }

I find the latter *much* clearer.

Great, then you are lucky, because you *can* write it that way. Now
allow me too writing it how I want writing it and everyone is happy! <3

Best regards
Tim Düsterhus

--

Cheers
Nick

(Not sure where in the thread to put this, so just replying to the most recent 
message.)

It's worth noting that in C# (not sure about the other languages) it's possible 
to set the default value of a non-promoted property to an expression that 
includes the primary constructor parameters.  The example from the C# docs[1]

public struct Distance(double dx, double dy)
{
 public readonly double Magnitude => Math.Sqrt(dx * dx + dy * dy);
 public readonly double Direction => Math.Atan2(dy, dx);
}

Which in PHP would look something like this:

class Distance(float $dx, float $dy)
{
 public readonly float $magnitude = sqrt($dx * $dx + $dy * $dy);
 public readonly float $direction = atan2($dy, $dx);
}

I'm not saying we should adopt that approach, necessarily.  I'm just noting it as a 
possible workaround for "i want a primary constructor and a tiny bit of 
post-processing", if an init block isn't an acceptable.  (I'm not sure how exactly 
that overlaps with property accessors; maybe it's the same thing?)

It sounds like Nick and Tim are fundamentally split on having an init block 
(however it's spelled).  I'm impartial.  I can see the use for it, but I also 
would be OK if it is punted for later.  I'd also be OK with exploring a 
C#-style approach as above.

As far as size/scope, RFCs should be "self-complete."  They should offer some 
functionality that is useful on its own, even if it gets multiplied by some other RFC.  Sometimes 
that means split it up, sometimes it means combine it.  Right-sizing an RFC is not about making it 
as small as possible or as far-reaching as possible.  So if the result of the discussion is that we 
do need to double the length of the RFC to include a constructor init block of some kind, so be it. 
 That's not a bad thing if the result is a better feature.  Nor is leaving it out bad if the result 
is a better feature.  The goal should be "a complete and robust feature", not big or 
small chunks.

[1]https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/primary-constructors#create-mutable-state

--Larry Garfield



Thanks, Larry.
I'd like to take the chance to address Rob's "would explode the 
complexity of the RFC", because I honestly don't see it. I keep the 
following examples focused on the parent constructor calling; omitting 
any unrelated noise.



```

final readonly class Dog(
string $name,
)extends Animal {
parent::__construct($name);
}=> {
// class body }

```

The above:
- does NOT have a parent constructor shortcut call -> `extends Animal`
- DOES allow parent constructor call in primary constructor body
- behaves exactly (!) as a conventional constructor; in fact syntax sugar

```

final readonly class Dog(
string $name,
)extends Animal($name)// already IS the parent constructor call... {
// hence, here no parent constructor call allowed }=> {
// class body }

```

The above:
- DOES have a parent constructor shortcut call -> `extends Animal($name)`
- does NOT allow parent constructor call in primary constructor body
- *no difference in parent constructor calling behaviour to what the RFC 
proposes now*


It's easy to reason about with: "either parent constructor OR parent 
constructor shortcut can be called".


It does not need a new name like "init block", it's a constructor body 
on the primary constructor. Which works as any other conventional 
constructor body, because it is syntax sugar. So where is the 
complexity? What would justify not allowing the body that helps to 
address a real problem?


--

Cheers
Nick


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-30 Thread Larry Garfield
On Mon, Jun 29, 2026, at 3:56 PM, Nick Sdot wrote:

>>     final readonly class Foo(Collection|array $value) implements Bar {
>>     $this->items = $value instanceof Collection ? $value : new 
>> Collection($value);
>>     } => {
>>     public Collection $items;
>>
>>     // class body private Collection $items
>>     }
>>
>>     final readonly class Foo implements Bar {
>>     public Collection $items;
>>
>>     public function __construct(Collection|array $value) {
>>     $this->items = $value instanceof Collection ? $value : new 
>> Collection($value);
>>     }
>>
>>     // class body private Collection $items
>>     }
>>
>> I find the latter *much* clearer.
>
> Great, then you are lucky, because you *can* write it that way. Now 
> allow me too writing it how I want writing it and everyone is happy! <3
>> Best regards
>> Tim Düsterhus 
>
> --
>
> Cheers
> Nick

(Not sure where in the thread to put this, so just replying to the most recent 
message.)

It's worth noting that in C# (not sure about the other languages) it's possible 
to set the default value of a non-promoted property to an expression that 
includes the primary constructor parameters.  The example from the C# docs[1]

public struct Distance(double dx, double dy)
{
public readonly double Magnitude => Math.Sqrt(dx * dx + dy * dy);
public readonly double Direction => Math.Atan2(dy, dx);
}

Which in PHP would look something like this:

class Distance(float $dx, float $dy)
{
public readonly float $magnitude = sqrt($dx * $dx + $dy * $dy);
public readonly float $direction = atan2($dy, $dx);
}

I'm not saying we should adopt that approach, necessarily.  I'm just noting it 
as a possible workaround for "i want a primary constructor and a tiny bit of 
post-processing", if an init block isn't an acceptable.  (I'm not sure how 
exactly that overlaps with property accessors; maybe it's the same thing?)

It sounds like Nick and Tim are fundamentally split on having an init block 
(however it's spelled).  I'm impartial.  I can see the use for it, but I also 
would be OK if it is punted for later.  I'd also be OK with exploring a 
C#-style approach as above.

As far as size/scope, RFCs should be "self-complete."  They should offer some 
functionality that is useful on its own, even if it gets multiplied by some 
other RFC.  Sometimes that means split it up, sometimes it means combine it.  
Right-sizing an RFC is not about making it as small as possible or as 
far-reaching as possible.  So if the result of the discussion is that we do 
need to double the length of the RFC to include a constructor init block of 
some kind, so be it.  That's not a bad thing if the result is a better feature. 
 Nor is leaving it out bad if the result is a better feature.  The goal should 
be "a complete and robust feature", not big or small chunks.

[1] 
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/primary-constructors#create-mutable-state

--Larry Garfield


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Nick Sdot

Hey Tim,

On 30.06.26 04:27, Tim Düsterhus wrote:

Hi

Am 2026-06-29 22:06, schrieb Nick Sdot:

```

final readonly class Foo(Collection|array $value) implementsBar {
    $this->items = $value instanceof Collection ? $value : new 
Collection($value);

}=> {
    // class body private Collection $items

}

```

How is this not easy to reason about? How is this not *less* confusing?


By introducing `=> {` as a new syntactical pattern that we don't 
currently have and where we would need to figure out whether that 
pattern would be consistent with existing use of `=>`. My gut feeling 
is “it isn’t”.
I have literally zero strong opinion on how the syntax must look like; 
as mentioned in my very first answer to Rowan (discussion 1), this is 
meant to illustrate the concept and placement, not syntax.


I'm also noting that your example doesn't declare the `$items` 
property, which to me is an indicator that it actually isn't that easy 
to reason about. 


It does declare it; for some reason it just slipped up behind the "class 
body" comment -- which is not the case in my sent mails.
“Reduce typing” alone is not a sufficiently strong argument in favor 
of a new feature.


Not sure how reduce typing is related to the argument I am making? My 
point is that I *want* primary constructors, but that they should 
allow bodies to have the same workarounds at hand to deal with 
readonly and hook issues as with conventional constructors.


The stated goal of the RFC (from the introduction) is: “removing […] 
boilerplate”. It specifically does so by allowing to omit `public 
function __construct`, `parent::__construct`, and a pair of braces. 
Personally I don't see much value in “just avoid typing some 
characters”. However for “logic-less” classes that just store some 
values, I can see where the proposal is coming from and the guarantee 
that the constructor actually is “logic-less” is some - small - 
benefit over “avoid typing characters that your IDE will autocomplete”.


This small benefit would entirely go away by allowing arbitrary logic 
in the constructor - and then as you said we would “[…] need to find 
an agreement on how parent constructor stuff works”, which is adding 
*extra* semantics that folks need to learn onto a feature that is 
supposed to make things *simpler*.


Quoting myself: "usage of parent constructor shortcut forbids manual 
parent constructor calling, and vice versa. Makes sense to me, and 
sounds easy to reason about."


Staying with your example above, but declaring `$items`, I've come up 
with the following:


    final readonly class Foo(Collection|array $value) implements Bar {
    $this->items = $value instanceof Collection ? $value : new 
Collection($value);

    } => {
    public Collection $items;

    // class body private Collection $items
    }

    final readonly class Foo implements Bar {
    public Collection $items;

    public function __construct(Collection|array $value) {
    $this->items = $value instanceof Collection ? $value : new 
Collection($value);

    }

    // class body private Collection $items
    }

I find the latter *much* clearer.


Great, then you are lucky, because you *can* write it that way. Now 
allow me too writing it how I want writing it and everyone is happy! <3

Best regards
Tim Düsterhus 


--

Cheers
Nick


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Tim Düsterhus

Hi

Am 2026-06-29 22:06, schrieb Nick Sdot:

```

final readonly class Foo(Collection|array $value) implementsBar {
$this->items = $value instanceof Collection ? $value : new 
Collection($value);

}=> {
// class body private Collection $items

}

```

How is this not easy to reason about? How is this not *less* confusing?


By introducing `=> {` as a new syntactical pattern that we don't 
currently have and where we would need to figure out whether that 
pattern would be consistent with existing use of `=>`. My gut feeling is 
“it isn’t”.


I'm also noting that your example doesn't declare the `$items` property, 
which to me is an indicator that it actually isn't that easy to reason 
about.


“Reduce typing” alone is not a sufficiently strong argument in favor 
of a new feature.


Not sure how reduce typing is related to the argument I am making? My 
point is that I *want* primary constructors, but that they should allow 
bodies to have the same workarounds at hand to deal with readonly and 
hook issues as with conventional constructors.


The stated goal of the RFC (from the introduction) is: “removing […] 
boilerplate”. It specifically does so by allowing to omit `public 
function __construct`, `parent::__construct`, and a pair of braces. 
Personally I don't see much value in “just avoid typing some 
characters”. However for “logic-less” classes that just store some 
values, I can see where the proposal is coming from and the guarantee 
that the constructor actually is “logic-less” is some - small - benefit 
over “avoid typing characters that your IDE will autocomplete”.


This small benefit would entirely go away by allowing arbitrary logic in 
the constructor - and then as you said we would “[…] need to find an 
agreement on how parent constructor stuff works”, which is adding 
*extra* semantics that folks need to learn onto a feature that is 
supposed to make things *simpler*.


Staying with your example above, but declaring `$items`, I've come up 
with the following:


final readonly class Foo(Collection|array $value) implements Bar {
$this->items = $value instanceof Collection ? $value : new 
Collection($value);

} => {
public Collection $items;

// class body private Collection $items
}

final readonly class Foo implements Bar {
public Collection $items;

public function __construct(Collection|array $value) {
$this->items = $value instanceof Collection ? $value : new 
Collection($value);

}

// class body private Collection $items
}

I find the latter *much* clearer.

Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Tim Düsterhus

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. `#[ParamAttr] public int $x` appears on the property too, but 
newInstance() from ReflectionProperty errors.
   2. `#[PropAttr] public int $x` appears 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.


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 `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


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rob Landers


On Mon, Jun 29, 2026, at 18:59, Larry Garfield wrote:

[snip]

> The RFC has no mention of attributes.  An example of that would be helpful, 
> even though I presume it's exactly what one would expect it to be.

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. `#[ParamAttr] public int $x` appears on the property too, but 
newInstance() from ReflectionProperty errors.
   2. `#[PropAttr] public int $x` appears 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.

> The one addition I would ask for is to note that in Kotlin and Swift, there 
> is a post-primary-constructor initializer, called an `init` block.  It has no 
> body, but lets you do post-property-assignment stuff.  It's basically an 
> argument-free constructor.  I think that would go a long way toward smoothing 
> the concerns people have about this feature being too "locked down."
> 
> If we don't want a new keyword for it, we could allow a __construct method 
> that has NO arguments if there is a primary constructor.  It would get called 
> last, after everything else (including parent constructors if appropriate) 
> has run.  (Whether it's spelled `__construct() { ]]` or `__construct {  }`, I 
> don't have a strong opinion.)  A __construct that does take arguments would 
> still be a compile-time conflict with a primary constructor.
> 
> --Larry Garfield
> 

I believe this should be a follow-up RFC. In PHP, the child decides when to 
call the parent constructor — so "runs last, after parent constructors" 
requires defining a new sequencing contract, which is a real design decision 
that deserves its own discussion rather than a rider on this one. Beyond that, 
it also requires defining a syntax (you've sketched one approach, Nick another 
-- both are interesting and that's exactly why it needs its own discussion), 
rules (whether property lists should exist), and semantics. In essence, the 
description would be a large (probably half) of the current RFC.

— Rob

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Nick Sdot


On 30.06.26 03:47, Rob Landers wrote:



On Mon, Jun 29, 2026, at 21:20, Nick Sdot wrote:


Hey Rob,

On 29.06.26 21:35, Rob Landers wrote:

On Mon, Jun 29, 2026, at 13:42, Nick Sdot wrote:


Hey Rob,

On 29.06.26 19:03, Rob Landers wrote:

Hi, Nick,

On Mon, Jun 29, 2026, at 10:47, Nick Sdot wrote:

Hey Rowan,

On 29.06.26 16:00, Rowan Tommins [IMSoP] wrote:
> On 29/06/2026 07:31, Nick Sdot wrote:
>>
>> If "use conventional constructors, if you need `readonly` 
classes"
>> stands, then the same can be argued for everything else in the 
RFC.

>>
>
> For the record, my view is completely the opposite: if the new 
syntax

> allows everything a normal constructor does, just in a slightly
> different position, it will lead to endless style discussions 
of which

> to use.


That's a fair opinion, and not unexpected. Personally, I oppose
introducing more inconsistencies to PHP. Looks like that we need 
to have

these discussions then?


There's no inconsistency here.


The inconsistency is that we will have two kind of constructors. 
One that has a body, one has not. It's a completely new concept, 
but you talk about syntax sugar.


There's only one constructor; PHP doesn't allow you to have 
different constructors. You choose the spelling that makes the most 
sense for your class and objectives. This is just declaration, not 
logic.

Dude...


It only prevents you from initialization/validation in a body 
because there are no bodies. 



Right. Which makes them useless in endless situations.



Of all the PHP code on my machine (production application code, 
frameworks like symfony/laravel/doctrine) ... it's about 30-40% of 
all constructors that are completely empty. I also sent an LLM to 
look further at things that could benefit from this (ie, promote 
properties on older code instead of just empty constructors). It 
came back with 71% of Laravel and 61% of Symfony that could use 
Primary Constructors. I'm not saying they should go rewrite their 
code or anything like that, but that basically means at least 1-2 
out of 3 classes written in a given codebase could use primary 
constructors to simplify their construction and make it easier to skim.


My 2¢: I don't think this is useless.
I did not say it is useless, I did say it is useless in endless 
situations. And it is avoidable, by allowing a body.
If you need a body, use a constructor -- that's what they're for. 


But then I cannot benefit from the position (at the top of the 
class) of the primary constructors, which I really would like. 
Shouldn't we try to make each new feature as useful as possible? 
What are the actual blockers to not support primary constructor bodies?


There is nothing preventing a follow-up RFC from being proposed, but 
as well as anonymous classes, it deserves its own RFC. There's a lot 
of syntax to bike-shed, as well as questions like "if I give a body, 
can I still use a parent constructor shortcut?" It is not 
straightforward and nor should it be. I fully explored this in the 
Records RFC, and many people pushed back on the logic, even pointed 
out unsoundness in what seemed like an otherwise sound design.


Well, this is going to be more of a general thing, nothing exclusive 
to your RFC... But this is how we end up with more and more half 
finished and awkward (to not say broken) features in PHP. While I 
understand and generally support "get the minimum in and iterate 
later" from the perspective of RFC authors, reality shows that 
"later" can be either years later or very likely never at all. 
Though, we will have to deal with the unfinished/broken "minimum" 
solutions. How many more of these do we want to add?


To name three from the top of my mind:
1/ we still don't have stringable enums
2/ we still don't have a solution for widening the type of a promoted 
property's set hooks (hi #16638), and of course

3/ my beloved readonly hooks themselves. ;)

You know, I don't argue for the sake of it. It's just too often that 
my concerns turn out to be valid, eventually. See my comment to 
#16638; we probably should just have skipped hooks on promoted 
properties unless there would have been a solution before release. 
Now we have to deal with this inconsistent and broken behaviour for 
forever (?), because people are already busy with the next features. 
If we already not get such features right (no blame to anyone -- it's 
complex!), imagine what a disaster introducing native inline generics 
(with all its "good follow up RFC") could have lead to, if they would 
have made it in the language before PHP even has the will to agree on 
an internals approved official PHPDoc types spec that can prove 
itself over a few years without breaking code.


Point is, I care. That's why I voice my concerns.



The irony here is that this is a follow-up RFC born weeks after 
someone reminded me about this part of it. It was abandoned due to 
comments like this.


I do think I have a track record of attempting interesting RFCs and 

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Nick Sdot

Hey Tim,

On 30.06.26 03:37, Tim Düsterhus wrote:

Hi

Am 2026-06-29 21:20, schrieb Nick Sdot:
Well, this is going to be more of a general thing, nothing exclusive 
to your RFC... But this is how we end up with more and more half 
finished and awkward (to not say broken) features in PHP. While I 
understand and generally support "get the minimum in and iterate 
later" from the perspective of RFC authors, reality shows that 
"later" can be either years later or very likely never at all. 
Though, we will have to deal with the unfinished/broken "minimum" 
solutions. How many more of these do we want to add?


To name three from the top of my mind:
1/ we still don't have stringable enums
2/ we still don't have a solution for widening the type of a promoted 
property's set hooks (hi #16638), and of course

3/ my beloved readonly hooks themselves. ;)


I consider (1) and (3) to be fundamentally wrong from a semantic 
perspective, i.e. a “Won’t fix”, not a missing feature.


For (2) I agree that the situation is unfortunate, but as you say:

[…] See my comment to #16638; we probably should just have skipped 
hooks on promoted properties unless there would have been a solution 
before release.


… here the correct fix would've been making the feature *smaller* 
rather than *larger*, which is the opposite of what you are proposing 
here.
And for this RFC I agree with Rob that not allowing an explicit body 
with “primary constructors” is the correct choice to prevent 
confusion: The limitations are a feature that makes classes using 
“Primary Constructors” easy to reason about. “Reduce typing” alone is 
not a sufficiently strong argument in favor of a new feature. As an 
example, promoted properties are not just “fewer characters to type”, 
but have the added benefit of “keeping data types in sync between 
parameter and property”, thus reducing mistakes. I don't see such a 
benefit for primary constructors if they are capable of doing 
everything a regular constructor can.


Yes, as I proposed back then. However, I disagree. Making it "smaller" 
is not always automatically the solution. Here it is making it bigger. 
Because making it bigger makes primary constructor behave the same way 
as conventional constructors (with the benefit to be in the class 
header, which I find awesome). I don't see why I should not be allowed 
to write something like this:



```

final readonly class Foo(Collection|array $value) implementsBar {
$this->items = $value instanceof Collection ? $value : new 
Collection($value);
}=> {
// class body private Collection $items

}

```

How is this not easy to reason about? How is this not *less* confusing? 
It offers the same functionality as a normal constructor. It also would 
not prevent parent class constructor shortcuts or whatever. It in fact 
would not change/remove anything the RFC wants, and it is purely 
additive. If my understanding of Rob is correct, we just would need to 
find an agreement on how parent constructor stuff works.


“Reduce typing” alone is not a sufficiently strong argument in favor 
of a new feature.


Not sure how reduce typing is related to the argument I am making? My 
point is that I *want* primary constructors, but that they should allow 
bodies to have the same workarounds at hand to deal with readonly and 
hook issues as with conventional constructors.

Best regards
Tim Düsterhus

--

Cheers
Nick

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rob Landers


On Mon, Jun 29, 2026, at 21:20, Nick Sdot wrote:
> Hey Rob,
> 
> On 29.06.26 21:35, Rob Landers wrote:
>> On Mon, Jun 29, 2026, at 13:42, Nick Sdot wrote:
>>> Hey Rob,
>>> 
>>> On 29.06.26 19:03, Rob Landers wrote:
 Hi, Nick,
 
 On Mon, Jun 29, 2026, at 10:47, Nick Sdot wrote:
> Hey Rowan,
> 
> On 29.06.26 16:00, Rowan Tommins [IMSoP] wrote:
> > On 29/06/2026 07:31, Nick Sdot wrote:
> >>
> >> If "use conventional constructors, if you need `readonly` classes" 
> >> stands, then the same can be argued for everything else in the RFC.
> >>
> >
> > For the record, my view is completely the opposite: if the new syntax 
> > allows everything a normal constructor does, just in a slightly 
> > different position, it will lead to endless style discussions of which 
> > to use.
> 
> 
> That's a fair opinion, and not unexpected. Personally, I oppose 
> introducing more inconsistencies to PHP. Looks like that we need to have 
> these discussions then?
 
 There's no inconsistency here. 
>>> 
>>> The inconsistency is that we will have two kind of constructors. One that 
>>> has a body, one has not. It's a completely new concept, but you talk about 
>>> syntax sugar.
>> 
>> There's only one constructor; PHP doesn't allow you to have different 
>> constructors. You choose the spelling that makes the most sense for your 
>> class and objectives. This is just declaration, not logic.
> Dude...
>> 
 It only prevents you from initialization/validation in a body because 
 there are no bodies. 
>>> 
>>> Right. Which makes them useless in endless situations.
>>> 
>> 
>> Of all the PHP code on my machine (production application code, frameworks 
>> like symfony/laravel/doctrine) ... it's about 30-40% of all constructors 
>> that are completely empty. I also sent an LLM to look further at things that 
>> could benefit from this (ie, promote properties on older code instead of 
>> just empty constructors). It came back with 71% of Laravel and 61% of 
>> Symfony that could use Primary Constructors. I'm not saying they should go 
>> rewrite their code or anything like that, but that basically means at least 
>> 1-2 out of 3 classes written in a given codebase could use primary 
>> constructors to simplify their construction and make it easier to skim.
>> 
>> My 2¢: I don't think this is useless.
> I did not say it is useless, I did say it is useless in endless situations. 
> And it is avoidable, by allowing a body.
 If you need a body, use a constructor -- that's what they're for. 
>>> 
>>> But then I cannot benefit from the position (at the top of the class) of 
>>> the primary constructors, which I really would like. Shouldn't we try to 
>>> make each new feature as useful as possible? What are the actual blockers 
>>> to not support primary constructor bodies?
>> 
>> There is nothing preventing a follow-up RFC from being proposed, but as well 
>> as anonymous classes, it deserves its own RFC. There's a lot of syntax to 
>> bike-shed, as well as questions like "if I give a body, can I still use a 
>> parent constructor shortcut?" It is not straightforward and nor should it 
>> be. I fully explored this in the Records RFC, and many people pushed back on 
>> the logic, even pointed out unsoundness in what seemed like an otherwise 
>> sound design.
> Well, this is going to be more of a general thing, nothing exclusive to your 
> RFC... But this is how we end up with more and more half finished and awkward 
> (to not say broken) features in PHP. While I understand and generally support 
> "get the minimum in and iterate later" from the perspective of RFC authors, 
> reality shows that "later" can be either years later or very likely never at 
> all. Though, we will have to deal with the unfinished/broken "minimum" 
> solutions. How many more of these do we want to add? 
> 
> To name three from the top of my mind: 
> 1/ we still don't have stringable enums 
> 2/ we still don't have a solution for widening the type of a promoted 
> property's set hooks (hi #16638), and of course 
> 3/ my beloved readonly hooks themselves. ;)
> 
> You know, I don't argue for the sake of it. It's just too often that my 
> concerns turn out to be valid, eventually. See my comment to #16638; we 
> probably should just have skipped hooks on promoted properties unless there 
> would have been a solution before release. Now we have to deal with this 
> inconsistent and broken behaviour for forever (?), because people are already 
> busy with the next features. If we already not get such features right (no 
> blame to anyone -- it's complex!), imagine what a disaster introducing native 
> inline generics (with all its "good follow up RFC") could have lead to, if 
> they would have made it in the language before PHP even has the will to agree 
> on an internals approved official PHPDoc types spec that can prove itself 
> over a few years without breaking code.

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Tim Düsterhus

Hi

Am 2026-06-29 21:21, schrieb Seifeddine Gmati:
I don't think the "seek to the constructor" problem is real in 
practice.

By convention the constructor goes first in a PHP class, so the code
you'd be reading is simply:

```
class Foo extends Base
{
  public function __construct(public int $a, public string $b)
  {
parent::__construct($a, $b);
  }
}
```

That's seven lines that fit comfortably on any screen, and each 
concept,

the class, the constructor, the promoted properties, the parent call,
sits on its own line where it's immediately recognizable. Packing all 
of

it onto a single line saves nothing and makes the code harder to read,
not easier.

I also disagree with comparing this to promoted properties. Promoted
properties removed genuine boilerplate: the property declaration, the
constructor parameter, and the `$this->x = $x` assignment collapsed 
into

one place because they were the same information repeated three times.
Primary constructors don't remove repetition; they just relocate the
constructor signature into the class declaration line. There's no
duplicated information being eliminated.


And even though I just argued in favor of the current proposal in a 
reply to Nick (https://news-web.php.net/php.internals/131614), I also 
agree with Seifeddine, that I don’t think that the value provided by 
this proposal is sufficiently strong to get a “Yes” from me - but I know 
that allowing arbitrary bodies would be a “No”.


Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Tim Düsterhus

Hi

Am 2026-06-29 21:20, schrieb Nick Sdot:
Well, this is going to be more of a general thing, nothing exclusive to 
your RFC... But this is how we end up with more and more half finished 
and awkward (to not say broken) features in PHP. While I understand and 
generally support "get the minimum in and iterate later" from the 
perspective of RFC authors, reality shows that "later" can be either 
years later or very likely never at all. Though, we will have to deal 
with the unfinished/broken "minimum" solutions. How many more of these 
do we want to add?


To name three from the top of my mind:
1/ we still don't have stringable enums
2/ we still don't have a solution for widening the type of a promoted 
property's set hooks (hi #16638), and of course

3/ my beloved readonly hooks themselves. ;)


I consider (1) and (3) to be fundamentally wrong from a semantic 
perspective, i.e. a “Won’t fix”, not a missing feature.


For (2) I agree that the situation is unfortunate, but as you say:

[…] See my comment to #16638; we probably should just have skipped 
hooks on promoted properties unless there would have been a solution 
before release.


… here the correct fix would've been making the feature *smaller* rather 
than *larger*, which is the opposite of what you are proposing here.


And for this RFC I agree with Rob that not allowing an explicit body 
with “primary constructors” is the correct choice to prevent confusion: 
The limitations are a feature that makes classes using “Primary 
Constructors” easy to reason about. “Reduce typing” alone is not a 
sufficiently strong argument in favor of a new feature. As an example, 
promoted properties are not just “fewer characters to type”, but have 
the added benefit of “keeping data types in sync between parameter and 
property”, thus reducing mistakes. I don't see such a benefit for 
primary constructors if they are capable of doing everything a regular 
constructor can.


Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Nick Sdot

Hey Larry,

On 30.06.26 00:59, Larry Garfield wrote:

On Sun, Jun 28, 2026, at 7:17 PM, Rob Landers wrote:

Hello internals,

I'd like to put forward Primary Constructors
 for comment.

An implementation PR will be opened later today (UTC), and the RFC
updated with this discussion thread.

— Rob

I support this feature, and am glad to see it.  It will make struct-objects 
that much easier to write, as well as more interesting value objects.

To the objections about readonly... Seriously, readonly is broken. :-)  Use 
private(set) instead and you get essentially the same effect, unless you're 
doing something screwy inside your class.  And if you are, then you already 
know it.


I know you will not get tired trying to sell us private(set) -- but it's 
not the same; one prevents a programmer error, the other not. We cannot 
one time argue we need guardrails and don't hand out foot guns, and when 
it doesn't suit the argument we ignore it.



As Rob already noted, there's a massive number of existing classes where it's 
not even an issue: There's no hooks or need for them, and readonly works fine 
then.  Or switching them over to private(set) if adding a hook in the future is 
not hard.  (Unless there's inheritance involved, and then the problem is 
inheritance. :-) )

We can't remove readonly from the language, but we should not allow its 
limitations and flaws to keep us from making our lives easier.
Bud, you make it sound as if there would be no other solution. Simply 
allowing a body for primary constructors *is* the solution. And it 
doesn't require readonly to be removed from the language. ;)

The RFC has no mention of attributes.  An example of that would be helpful, 
even though I presume it's exactly what one would expect it to be.

The one addition I would ask for is to note that in Kotlin and Swift, there is a 
post-primary-constructor initializer, called an `init` block.  It has no body, but lets 
you do post-property-assignment stuff.  It's basically an argument-free constructor.  I 
think that would go a long way toward smoothing the concerns people have about this 
feature being too "locked down."

If we don't want a new keyword for it, we could allow a __construct method that 
has NO arguments if there is a primary constructor.  It would get called last, 
after everything else (including parent constructors if appropriate) has run.  
(Whether it's spelled `__construct() { ]]` or `__construct {  }`, I don't have 
a strong opinion.)  A __construct that does take arguments would still be a 
compile-time conflict with a primary constructor.

--Larry Garfield

--

Cheers
Nick


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Seifeddine Gmati
> It's also the entire point of the feature ;) You open the file, and in two 
> seconds, you know:
>
> It defines two properties, type int and string, it calls parent::__construct 
> with those two parameters.
>
> Currently, you open the class, seek to the constructor, read it to understand 
> if it even calls the parent constructor or not. Just like promoted 
> properties, the cost is nominal, but now it is nearly ubiquitous in usage and 
> saves a large amount of time in reading and writing classes. This feature 
> seeks to do the same.

> It's also the entire point of the feature ;) You open the file, and in
> two seconds, you know:
>
> It defines two properties, type int and string, it calls
> parent::__construct with those two parameters.
>
> Currently, you open the class, seek to the constructor, read it to
> understand if it even calls the parent constructor or not. Just like
> promoted properties, the cost is nominal, but now it is nearly
> ubiquitous in usage and saves a large amount of time in reading and
> writing classes. This feature seeks to do the same.

I don't think the "seek to the constructor" problem is real in practice.
By convention the constructor goes first in a PHP class, so the code
you'd be reading is simply:

```
class Foo extends Base
{
  public function __construct(public int $a, public string $b)
  {
parent::__construct($a, $b);
  }
}
```

That's seven lines that fit comfortably on any screen, and each concept,
the class, the constructor, the promoted properties, the parent call,
sits on its own line where it's immediately recognizable. Packing all of
it onto a single line saves nothing and makes the code harder to read,
not easier.

I also disagree with comparing this to promoted properties. Promoted
properties removed genuine boilerplate: the property declaration, the
constructor parameter, and the `$this->x = $x` assignment collapsed into
one place because they were the same information repeated three times.
Primary constructors don't remove repetition; they just relocate the
constructor signature into the class declaration line. There's no
duplicated information being eliminated.

Cheers,
Seifeddine.


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Tim Düsterhus

Hi

Am 2026-06-29 18:59, schrieb Larry Garfield:
The RFC has no mention of attributes.  An example of that would be 
helpful, even though I presume it's exactly what one would expect it to 
be.


I second that the RFC needs to specify this, *because* I don't consider 
this obvious at all and I'm positive that the expectations from users 
differ wildly. What do your expectations look like?


Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Nick Sdot

Hey Rob,

On 29.06.26 21:35, Rob Landers wrote:

On Mon, Jun 29, 2026, at 13:42, Nick Sdot wrote:


Hey Rob,

On 29.06.26 19:03, Rob Landers wrote:

Hi, Nick,

On Mon, Jun 29, 2026, at 10:47, Nick Sdot wrote:

Hey Rowan,

On 29.06.26 16:00, Rowan Tommins [IMSoP] wrote:
> On 29/06/2026 07:31, Nick Sdot wrote:
>>
>> If "use conventional constructors, if you need `readonly` classes"
>> stands, then the same can be argued for everything else in the RFC.
>>
>
> For the record, my view is completely the opposite: if the new 
syntax

> allows everything a normal constructor does, just in a slightly
> different position, it will lead to endless style discussions of 
which

> to use.


That's a fair opinion, and not unexpected. Personally, I oppose
introducing more inconsistencies to PHP. Looks like that we need to 
have

these discussions then?


There's no inconsistency here.


The inconsistency is that we will have two kind of constructors. One 
that has a body, one has not. It's a completely new concept, but you 
talk about syntax sugar.


There's only one constructor; PHP doesn't allow you to have different 
constructors. You choose the spelling that makes the most sense for 
your class and objectives. This is just declaration, not logic.

Dude...


It only prevents you from initialization/validation in a body 
because there are no bodies. 



Right. Which makes them useless in endless situations.



Of all the PHP code on my machine (production application code, 
frameworks like symfony/laravel/doctrine) ... it's about 30-40% of all 
constructors that are completely empty. I also sent an LLM to look 
further at things that could benefit from this (ie, promote properties 
on older code instead of just empty constructors). It came back with 
71% of Laravel and 61% of Symfony that could use Primary Constructors. 
I'm not saying they should go rewrite their code or anything like 
that, but that basically means at least 1-2 out of 3 classes written 
in a given codebase could use primary constructors to simplify their 
construction and make it easier to skim.


My 2¢: I don't think this is useless.
I did not say it is useless, I did say it is useless in endless 
situations. And it is avoidable, by allowing a body.
If you need a body, use a constructor -- that's what they're for. 


But then I cannot benefit from the position (at the top of the class) 
of the primary constructors, which I really would like. Shouldn't we 
try to make each new feature as useful as possible? What are the 
actual blockers to not support primary constructor bodies?


There is nothing preventing a follow-up RFC from being proposed, but 
as well as anonymous classes, it deserves its own RFC. There's a lot 
of syntax to bike-shed, as well as questions like "if I give a body, 
can I still use a parent constructor shortcut?" It is not 
straightforward and nor should it be. I fully explored this in the 
Records RFC, and many people pushed back on the logic, even pointed 
out unsoundness in what seemed like an otherwise sound design.


Well, this is going to be more of a general thing, nothing exclusive to 
your RFC... But this is how we end up with more and more half finished 
and awkward (to not say broken) features in PHP. While I understand and 
generally support "get the minimum in and iterate later" from the 
perspective of RFC authors, reality shows that "later" can be either 
years later or very likely never at all. Though, we will have to deal 
with the unfinished/broken "minimum" solutions. How many more of these 
do we want to add?


To name three from the top of my mind:
1/ we still don't have stringable enums
2/ we still don't have a solution for widening the type of a promoted 
property's set hooks (hi #16638), and of course

3/ my beloved readonly hooks themselves. ;)

You know, I don't argue for the sake of it. It's just too often that my 
concerns turn out to be valid, eventually. See my comment to #16638; we 
probably should just have skipped hooks on promoted properties unless 
there would have been a solution before release. Now we have to deal 
with this inconsistent and broken behaviour for forever (?), because 
people are already busy with the next features. If we already not get 
such features right (no blame to anyone -- it's complex!), imagine what 
a disaster introducing native inline generics (with all its "good follow 
up RFC") could have lead to, if they would have made it in the language 
before PHP even has the will to agree on an internals approved official 
PHPDoc types spec that can prove itself over a few years without 
breaking code.


Point is, I care. That's why I voice my concerns.


"if I give a body, can I still use a parent constructor shortcut?"


My opinion: usage of parent constructor shortcut forbids manual parent 
constructor calling, and vice versa. Makes sense to me, and sounds easy 
to reason about.


Other people could see that different, yes. But that's why I think it 
should be discussed 

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rob Landers


On Mon, Jun 29, 2026, at 20:54, Seifeddine Gmati wrote:
> On Mon, 29 Jun 2026 at 01:18, Rob Landers  wrote:
> >
> > Hello internals,
> >
> > I'd like to put forward Primary Constructors for comment.
> >
> > An implementation PR will be opened later today (UTC), and the RFC updated 
> > with this discussion thread.
> >
> > — Rob
> 
> Hi Rob,
> 
> Personally, I really dislike this feature.

Sincerely, thank you for your opinion.

> 
> It adds a new syntax that increases the complexity of the PHP grammar,
> which is already quite complex, for no real advantage. It's just a
> slightly different way to write something the language already
> expresses.
> 
> It's also confusing to read. A line like:
> 
> ```
> class Foo(public int $a, public string $b) extends Base($a, $b) { ... }
> ```
> 
> jumps from class definition, to constructor definition, to class
> definition again (inheritance), to what is effectively a
> `parent::__construct()` call, and then back into the class body.
> That's a lot of distinct concepts packed into a single line, with no
> syntactic separation to signal the shift from one to the next.
> 
> Cheers,
> Seifeddine.

It's also the entire point of the feature ;) You open the file, and in two 
seconds, you know:

It defines two properties, type int and string, it calls parent::__construct 
with those two parameters.

Currently, you open the class, seek to the constructor, read it to understand 
if it even calls the parent constructor or not. Just like promoted properties, 
the cost is nominal, but now it is nearly ubiquitous in usage and saves a large 
amount of time in reading and writing classes. This feature seeks to do the 
same.

— Rob

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Tim Düsterhus

Hi

Am 2026-06-29 02:17, schrieb Rob Landers:
I'd like to put forward Primary Constructors 
 for comment.


The RFC currently does not specify the interaction with visibility. It 
is currently implied that the constructor will be `public`, but the RFC 
doesn't spell that out and doesn't specify whether or not it is possible 
to make such a constructor non-public (e.g. to actually treat it as a 
“primary constructor” in a sea of multiple named constructors).


Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Tim Düsterhus

Hi

Am 2026-06-29 20:44, schrieb Eric Norris:

I'm afraid of going off-topic, but I disagree that "readonly is
broken." In what way is it broken? A large part of the disagreement in
the previous "readonly hooks" RFC was over the *meaning* of readonly.
I'd have to fully go back to remind myself of the nuance, but my
recollection is that it works exactly how I (and others, per the vote
outcome) expect.

[…]

This is not meant to be a combative email by the way, I just want to
make sure it's clear that I believe readonly is not something that we
should remove or consider baggage.


I'm in full agreement on the quoted sections.

Best regards
Tim Düsterhus


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Seifeddine Gmati
On Mon, 29 Jun 2026 at 01:18, Rob Landers  wrote:
>
> Hello internals,
>
> I'd like to put forward Primary Constructors for comment.
>
> An implementation PR will be opened later today (UTC), and the RFC updated 
> with this discussion thread.
>
> — Rob

Hi Rob,

Personally, I really dislike this feature.

It adds a new syntax that increases the complexity of the PHP grammar,
which is already quite complex, for no real advantage. It's just a
slightly different way to write something the language already
expresses.

It's also confusing to read. A line like:

```
class Foo(public int $a, public string $b) extends Base($a, $b) { ... }
```

jumps from class definition, to constructor definition, to class
definition again (inheritance), to what is effectively a
`parent::__construct()` call, and then back into the class body.
That's a lot of distinct concepts packed into a single line, with no
syntactic separation to signal the shift from one to the next.

Cheers,
Seifeddine.


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Eric Norris
On Mon, Jun 29, 2026 at 2:01 PM Larry Garfield  wrote:
>
> On Sun, Jun 28, 2026, at 7:17 PM, Rob Landers wrote:
> > Hello internals,
> >
> > I'd like to put forward Primary Constructors
> >  for comment.
> >
> > An implementation PR will be opened later today (UTC), and the RFC
> > updated with this discussion thread.
> >
> > — Rob
>
> I support this feature, and am glad to see it.  It will make struct-objects 
> that much easier to write, as well as more interesting value objects.
>
> To the objections about readonly... Seriously, readonly is broken. :-)  Use 
> private(set) instead and you get essentially the same effect, unless you're 
> doing something screwy inside your class.  And if you are, then you already 
> know it.
>
> As Rob already noted, there's a massive number of existing classes where it's 
> not even an issue: There's no hooks or need for them, and readonly works fine 
> then.  Or switching them over to private(set) if adding a hook in the future 
> is not hard.  (Unless there's inheritance involved, and then the problem is 
> inheritance. :-) )
>
> We can't remove readonly from the language, but we should not allow its 
> limitations and flaws to keep us from making our lives easier.

I'm afraid of going off-topic, but I disagree that "readonly is
broken." In what way is it broken? A large part of the disagreement in
the previous "readonly hooks" RFC was over the *meaning* of readonly.
I'd have to fully go back to remind myself of the nuance, but my
recollection is that it works exactly how I (and others, per the vote
outcome) expect.

I recall that it seemed like what people wanted was to have something
only *publicly* readable, but internally writable, which is in fact
what you're suggesting as an alternative - asymmetric visibility
(private(set)) - and is not what readonly is for, even if the name
lends itself to confusion. I think you had even described it as
"write-once", at one point, which more closely matches my expectation
and desire of the keyword.

I recall that I (and someone else?) had thrown out a suggestion for
"init" hooks, that I think would have addressed what some people were
looking for (having a hook with a readonly property for
initialization), but not others (get hooks for readonly, since that
breaks the "main" interpretation of the readonly RFC). Again, this was
a while ago so I'm a little fuzzy, but I would absolutely consider
voting yes for an "init" hook RFC; I could arguably see that as
compatible with the readonly keyword, and thus, readonly would be
compatible with (a subset of) hooks.

This is not meant to be a combative email by the way, I just want to
make sure it's clear that I believe readonly is not something that we
should remove or consider baggage.


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rowan Tommins [IMSoP]
On 29 June 2026 17:40:29 BST, Larry Garfield  wrote:
>For anon classes, I would think the best approach is to have a compact, 
>non-redundant syntax for "take this value from current scope and assign it to 
>a property in this class."  Basically combining promotion and closure.  Doing 
>that right now is horribly ugly.

Yeah, that was precisely my starting point. The "use" syntax I came up with 
felt pretty clear and flexible, but some off-list review suggested that 
fabricating a constructor behind the scenes was not ideal, because there are 
use cases for combining it with a real constructor.

I was looking into alternative ways to inject the values into the instance, 
such as an extra opcode like the one closures use; but Real Life intervened and 
I haven't got back to it for a while.

I would need to look back at notes and discussions to see if there were use 
cases mentioned other than parent constructor calls. Maybe the "parameter 
forwarding" syntax from this RFC could be combined with what I had somehow.



Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Larry Garfield
On Sun, Jun 28, 2026, at 7:17 PM, Rob Landers wrote:
> Hello internals,
>
> I'd like to put forward Primary Constructors 
>  for comment.
>
> An implementation PR will be opened later today (UTC), and the RFC 
> updated with this discussion thread.
>
> — Rob

I support this feature, and am glad to see it.  It will make struct-objects 
that much easier to write, as well as more interesting value objects.

To the objections about readonly... Seriously, readonly is broken. :-)  Use 
private(set) instead and you get essentially the same effect, unless you're 
doing something screwy inside your class.  And if you are, then you already 
know it.

As Rob already noted, there's a massive number of existing classes where it's 
not even an issue: There's no hooks or need for them, and readonly works fine 
then.  Or switching them over to private(set) if adding a hook in the future is 
not hard.  (Unless there's inheritance involved, and then the problem is 
inheritance. :-) )

We can't remove readonly from the language, but we should not allow its 
limitations and flaws to keep us from making our lives easier.

The RFC has no mention of attributes.  An example of that would be helpful, 
even though I presume it's exactly what one would expect it to be.

The one addition I would ask for is to note that in Kotlin and Swift, there is 
a post-primary-constructor initializer, called an `init` block.  It has no 
body, but lets you do post-property-assignment stuff.  It's basically an 
argument-free constructor.  I think that would go a long way toward smoothing 
the concerns people have about this feature being too "locked down."

If we don't want a new keyword for it, we could allow a __construct method that 
has NO arguments if there is a primary constructor.  It would get called last, 
after everything else (including parent constructors if appropriate) has run.  
(Whether it's spelled `__construct() { ]]` or `__construct {  }`, I don't have 
a strong opinion.)  A __construct that does take arguments would still be a 
compile-time conflict with a primary constructor.

--Larry Garfield


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Larry Garfield
On Mon, Jun 29, 2026, at 5:52 AM, Rob Landers wrote:
> On Mon, Jun 29, 2026, at 12:27, Lynn wrote:
>> 
>> 
>> On Mon, Jun 29, 2026 at 2:20 AM Rob Landers  wrote:
>>> __
>>> Hello internals,
>>> 
>>> I'd like to put forward Primary Constructors 
>>>  for comment.
>>> 
>>> An implementation PR will be opened later today (UTC), and the RFC updated 
>>> with this discussion thread.
>>> 
>>> — Rob
>> 
>> I don't see any mention of anonymous classes, I assume they aren't 
>> compatible syntax wise? 
>
> Hi Lynn,
>
> That's a good observation! Originally, I had a whole section and 
> decided to strip it, then forgot to add it back as non-supported and 
> future scope. FWIW, I was originally going to support them with 
> something like:
>
> $arg = 'foo';
> $class = new class(public int $x = $arg) {}
>
> Which desugars to:
>
> $arg = 'foo';
> $class = new class($arg) {
>   public function __construct(public int $x) {}
> }
>
> There are a lot of caveats, which is why I dropped it for future scope:
>  1. it would require types on the input parameters to disambiguate 
> between arguments and properties
>  2. it gets weird if you don't specify a default value for the property 
> and makes it ambiguous as a constructor
>  3. which begs the question of always having a default
> In essence, it deserves its own RFC because there is a lot of subtlety 
> and only makes sense in the context that primary constructors exist in 
> the first place.
>
> I'll address it in the RFC, thanks!
>
> — Rob

For anon classes, I would think the best approach is to have a compact, 
non-redundant syntax for "take this value from current scope and assign it to a 
property in this class."  Basically combining promotion and closure.  Doing 
that right now is horribly ugly.

That may well be out of scope for this RFC, and that's fine, but I wanted to 
put that out there.

--Larry Garfield


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rob Landers
On Mon, Jun 29, 2026, at 13:42, Nick Sdot wrote:
> Hey Rob,
> 
> On 29.06.26 19:03, Rob Landers wrote:
>> Hi, Nick,
>> 
>> On Mon, Jun 29, 2026, at 10:47, Nick Sdot wrote:
>>> Hey Rowan,
>>> 
>>> On 29.06.26 16:00, Rowan Tommins [IMSoP] wrote:
>>> > On 29/06/2026 07:31, Nick Sdot wrote:
>>> >>
>>> >> If "use conventional constructors, if you need `readonly` classes" 
>>> >> stands, then the same can be argued for everything else in the RFC.
>>> >>
>>> >
>>> > For the record, my view is completely the opposite: if the new syntax 
>>> > allows everything a normal constructor does, just in a slightly 
>>> > different position, it will lead to endless style discussions of which 
>>> > to use.
>>> 
>>> 
>>> That's a fair opinion, and not unexpected. Personally, I oppose 
>>> introducing more inconsistencies to PHP. Looks like that we need to have 
>>> these discussions then?
>> 
>> There's no inconsistency here. 
> 
> The inconsistency is that we will have two kind of constructors. One that has 
> a body, one has not. It's a completely new concept, but you talk about syntax 
> sugar.

There's only one constructor; PHP doesn't allow you to have different 
constructors. You choose the spelling that makes the most sense for your class 
and objectives. This is just declaration, not logic.

>> It only prevents you from initialization/validation in a body because there 
>> are no bodies. 
> 
> Right. Which makes them useless in endless situations.
> 

Of all the PHP code on my machine (production application code, frameworks like 
symfony/laravel/doctrine) ... it's about 30-40% of all constructors that are 
completely empty. I also sent an LLM to look further at things that could 
benefit from this (ie, promote properties on older code instead of just empty 
constructors). It came back with 71% of Laravel and 61% of Symfony that could 
use Primary Constructors. I'm not saying they should go rewrite their code or 
anything like that, but that basically means at least 1-2 out of 3 classes 
written in a given codebase could use primary constructors to simplify their 
construction and make it easier to skim.

My 2¢: I don't think this is useless.

>> If you need a body, use a constructor -- that's what they're for. 
> 
> But then I cannot benefit from the position (at the top of the class) of the 
> primary constructors, which I really would like. Shouldn't we try to make 
> each new feature as useful as possible? What are the actual blockers to not 
> support primary constructor bodies?

There is nothing preventing a follow-up RFC from being proposed, but as well as 
anonymous classes, it deserves its own RFC. There's a lot of syntax to 
bike-shed, as well as questions like "if I give a body, can I still use a 
parent constructor shortcut?" It is not straightforward and nor should it be. I 
fully explored this in the Records RFC, and many people pushed back on the 
logic, even pointed out unsoundness in what seemed like an otherwise sound 
design.

>> The RFC makes it plain that bodies are rejected and why.
> 
> It's possible that I missed where the "why" was explained, but I don't see 
> explanations apart from "expressed in property hooks"; which I am here 
> pointing out will not work in readonly classes. Could you please make the 
> "why" more clear in the RFC?

Will do.

>> If you can provide a concrete reason why they should be allowed with a 
>> completely new syntax, that would be a good follow-up RFC; or even a 
>> competing one. If you disagree with the reasoning, I'd love to hear it.
> 
> The concrete reason is what I already mentioned: it will not work with 
> readonly classes and `private(set)` is not the same.
> It's not that readonly for value projects is a rare thing.

Where do you see in the RFC that it won't work with readonly classes, because 
that would be an error on my part? It explicitly does not prevent you from 
using any type of class except enums. If you're referring to the usage of 
primary constructors in combination with hooks and readonly, that's an 
orthogonal issue that belongs to the interaction between hooks and readonly and 
is far out of scope from this RFC. That is a limitation that exists today and 
this RFC does not strive to address it.

> 
>> — Rob
> --
> 
> Cheers
> Nick
> 

— Rob

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rowan Tommins [IMSoP]
On 29 June 2026 11:52:45 BST, Rob Landers  wrote:
>
> FWIW, I was originally going to support them with something like:
>
>$arg = 'foo';
>$class = new class(public int $x = $arg) {}
>
>Which desugars to:
>
>$arg = 'foo';
>$class = new class($arg) {
>  public function __construct(public int $x) {}
>}


I actually have a draft RFC kicking around for this, but using a different 
syntax inspired by closures:

$arg = 'foo';
$class = new class() use (public int $arg) {}

This allows a very concise version for very simple cases: 

$class = new class() use ($arg) {}


I even had a working implementation, but paused it to work out if a constructor 
could be allowed as well. If the syntax allowed for a parent constructor call, 
though, that might be enough for most use cases.

Although it's not obvious, anonymous classes are actually compiled once, and 
then constructed multiple times, which means the syntax is doing quite a lot 
more than constructor promotion.

I agree that it should be left as future scope to pin down exactly how it 
should look and work.


Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Nick Sdot

Hey Rob,

On 29.06.26 19:03, Rob Landers wrote:

Hi, Nick,

On Mon, Jun 29, 2026, at 10:47, Nick Sdot wrote:

Hey Rowan,

On 29.06.26 16:00, Rowan Tommins [IMSoP] wrote:
> On 29/06/2026 07:31, Nick Sdot wrote:
>>
>> If "use conventional constructors, if you need `readonly` classes"
>> stands, then the same can be argued for everything else in the RFC.
>>
>
> For the record, my view is completely the opposite: if the new syntax
> allows everything a normal constructor does, just in a slightly
> different position, it will lead to endless style discussions of which
> to use.


That's a fair opinion, and not unexpected. Personally, I oppose
introducing more inconsistencies to PHP. Looks like that we need to have
these discussions then?


There's no inconsistency here.


The inconsistency is that we will have two kind of constructors. One 
that has a body, one has not. It's a completely new concept, but you 
talk about syntax sugar.
It only prevents you from initialization/validation in a body because 
there are no bodies. 



Right. Which makes them useless in endless situations.

If you need a body, use a constructor -- that's what they're for. 


But then I cannot benefit from the position (at the top of the class) of 
the primary constructors, which I really would like. Shouldn't we try to 
make each new feature as useful as possible? What are the actual 
blockers to not support primary constructor bodies?

The RFC makes it plain that bodies are rejected and why.


It's possible that I missed where the "why" was explained, but I don't 
see explanations apart from "expressed in property hooks"; which I am 
here pointing out will not work in readonly classes. Could you please 
make the "why" more clear in the RFC?
If you can provide a concrete reason why they should be allowed with a 
completely new syntax, that would be a good follow-up RFC; or even a 
competing one. If you disagree with the reasoning, I'd love to hear it.


The concrete reason is what I already mentioned: it will not work with 
readonly classes and `private(set)` is not the same.

It's not that readonly for value projects is a rare thing.


— Rob


--

Cheers
Nick


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Lynn
On Mon, Jun 29, 2026 at 12:56 PM Rob Landers  wrote:

>
>
> On Mon, Jun 29, 2026, at 12:27, Lynn wrote:
>
>
>
> On Mon, Jun 29, 2026 at 2:20 AM Rob Landers  wrote:
>
>
> Hello internals,
>
> I'd like to put forward Primary Constructors
>  for comment.
>
> An implementation PR will be opened later today (UTC), and the RFC updated
> with this discussion thread.
>
> — Rob
>
>
> I don't see any mention of anonymous classes, I assume they aren't
> compatible syntax wise?
>
>
> Hi Lynn,
>
> That's a good observation! Originally, I had a whole section and decided
> to strip it, then forgot to add it back as non-supported and future scope.
> FWIW, I was originally going to support them with something like:
>
> $arg = 'foo';
> $class = new class(public int $x = $arg) {}
>
>
> Which desugars to:
>
> $arg = 'foo';
> $class = new class($arg) {
>   public function __construct(public int $x) {}
> }
>
>
> There are a lot of caveats, which is why I dropped it for future scope:
>
>1. it would require types on the input parameters to disambiguate
>between arguments and properties
>2. it gets weird if you don't specify a default value for the property
>and makes it ambiguous as a constructor
>3. which begs the question of always having a default
>
> In essence, it deserves its own RFC because there is a lot of subtlety and
> only makes sense in the context that primary constructors exist in the
> first place.
>
> I'll address it in the RFC, thanks!
>
> — Rob
>

I think the only thing that needs to be solved for anonymous classes would
be the syntax. Seeing there's always a visibility/type in property
promotion, I think it should be clear it's going to be style (A) or (B)
based on the syntax as you can't mix. I can't see a scenario where you
would write:

$class = new class(public int $x) {}

Where as the following would be just fine:

$class = new class(public int $x = 0) {};  // construct with
property $x being 0
$class = new class(public int|null $x = null) {};  // construct with
property $x being null
$class = new class(public int $x = $x) {}; // construct with
$x from local scope into property $x
$class = new class(public int $x = $this->x) {};   // construct with
$this->x from the instance scope
$class = new class(public int $x = self::$x) {};   // construct with
$this->x from the static self scope

Bonus points if the body becomes optional:

$class = new class(public int $x = 0, public int $y = 0);

This would be the existing style and remains unchanged

$class = new class($localScope) {};

Mixing would error as you can't pick both:

$class = new class(public int $x = 0, $y) {}; // Nothing handles $y as
no body is allowed
$class = new class($x, public int $y = 0) {}; // Can't allow the
latter as $x requires a body to do something


Perhaps this isn't as simple as I think it is, but this would be a nice +
to have in this RFC. I think it's fine to keep the initial implementation
rather restrictive, it can always be improved upon in the future.


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rob Landers
On Mon, Jun 29, 2026, at 02:17, Rob Landers wrote:
> Hello internals,
> 
> I'd like to put forward Primary Constructors 
>  for comment.
> 
> An implementation PR will be opened later today (UTC), and the RFC updated 
> with this discussion thread.
> 
> — Rob

I've updated the RFC with an implementation URL, the link to the mailing list 
thread, and information regarding anonymous classes.

— Rob

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rob Landers
Hi, Nick,

On Mon, Jun 29, 2026, at 10:47, Nick Sdot wrote:
> Hey Rowan,
> 
> On 29.06.26 16:00, Rowan Tommins [IMSoP] wrote:
> > On 29/06/2026 07:31, Nick Sdot wrote:
> >>
> >> If "use conventional constructors, if you need `readonly` classes" 
> >> stands, then the same can be argued for everything else in the RFC.
> >>
> >
> > For the record, my view is completely the opposite: if the new syntax 
> > allows everything a normal constructor does, just in a slightly 
> > different position, it will lead to endless style discussions of which 
> > to use.
> 
> 
> That's a fair opinion, and not unexpected. Personally, I oppose 
> introducing more inconsistencies to PHP. Looks like that we need to have 
> these discussions then?

There's no inconsistency here. This syntax doesn't prevent you from using 
readonly classes. It only prevents you from initialization/validation in a body 
because there are no bodies. If you need a body, use a constructor -- that's 
what they're for. The RFC makes it plain that bodies are rejected and why. If 
you can provide a concrete reason why they should be allowed with a completely 
new syntax, that would be a good follow-up RFC; or even a competing one. If you 
disagree with the reasoning, I'd love to hear it.

— Rob

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rob Landers


On Mon, Jun 29, 2026, at 12:27, Lynn wrote:
> 
> 
> On Mon, Jun 29, 2026 at 2:20 AM Rob Landers  wrote:
>> __
>> Hello internals,
>> 
>> I'd like to put forward Primary Constructors 
>>  for comment.
>> 
>> An implementation PR will be opened later today (UTC), and the RFC updated 
>> with this discussion thread.
>> 
>> — Rob
> 
> I don't see any mention of anonymous classes, I assume they aren't compatible 
> syntax wise? 

Hi Lynn,

That's a good observation! Originally, I had a whole section and decided to 
strip it, then forgot to add it back as non-supported and future scope. FWIW, I 
was originally going to support them with something like:

$arg = 'foo';
$class = new class(public int $x = $arg) {}

Which desugars to:

$arg = 'foo';
$class = new class($arg) {
  public function __construct(public int $x) {}
}

There are a lot of caveats, which is why I dropped it for future scope:
 1. it would require types on the input parameters to disambiguate between 
arguments and properties
 2. it gets weird if you don't specify a default value for the property and 
makes it ambiguous as a constructor
 3. which begs the question of always having a default
In essence, it deserves its own RFC because there is a lot of subtlety and only 
makes sense in the context that primary constructors exist in the first place.

I'll address it in the RFC, thanks!

— Rob

Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Lynn
On Mon, Jun 29, 2026 at 2:20 AM Rob Landers  wrote:

> Hello internals,
>
> I'd like to put forward Primary Constructors
>  for comment.
>
> An implementation PR will be opened later today (UTC), and the RFC updated
> with this discussion thread.
>
> — Rob
>

I don't see any mention of anonymous classes, I assume they aren't
compatible syntax wise?


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Nick Sdot

Hey Rowan,

On 29.06.26 16:00, Rowan Tommins [IMSoP] wrote:

On 29/06/2026 07:31, Nick Sdot wrote:


If "use conventional constructors, if you need `readonly` classes" 
stands, then the same can be argued for everything else in the RFC.




For the record, my view is completely the opposite: if the new syntax 
allows everything a normal constructor does, just in a slightly 
different position, it will lead to endless style discussions of which 
to use.



That's a fair opinion, and not unexpected. Personally, I oppose 
introducing more inconsistencies to PHP. Looks like that we need to have 
these discussions then?


In fact, I don't think even property hooks belong in a primary 
constructor; they're ugly enough in a constructor promoted property.


It's a feature that was accepted to PHP and exists already. So it 
doesn't really matter whether we (I agree -- shouldn't be used for 
anything more than eg a neat callback) find it ugly and we have to deal 
with its existence. You are basically making a point for allowing 
primary constructor bodies. Having them allows to have a readonly 
classes with primary constructors, and assign properties in their body. 
Neat.


I think it's perfectly fine to have short-hands that only cover 
specific use cases, and longer forms that let you express more complex 
use cases. It's one of the reasons I voted against the recent RFC to 
allow an extra reassignment of properties in the constructor 
[https://wiki.php.net/rfc/promoted_readonly_constructor_reassign]. 



For the record, my view is completely the opposite: without allowing 
primary constructor bodies the added value of adding the new syntax is 
nearly non-existent.


Quoting from your message in the first thread to this:

I don't think we should add extra syntax to the language just to 
change people's habits. If you want a constructor body as the first 
thing in the class, you can do that right now.



...because the exact argument can be made from either point of view. To 
quote you again: "all or nothing"; bodies should be allowed.


--

Cheers
Nick


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-29 Thread Rowan Tommins [IMSoP]

On 29/06/2026 07:31, Nick Sdot wrote:


If "use conventional constructors, if you need `readonly` classes" 
stands, then the same can be argued for everything else in the RFC.




For the record, my view is completely the opposite: if the new syntax 
allows everything a normal constructor does, just in a slightly 
different position, it will lead to endless style discussions of which 
to use.


In fact, I don't think even property hooks belong in a primary 
constructor; they're ugly enough in a constructor promoted property.


I think it's perfectly fine to have short-hands that only cover specific 
use cases, and longer forms that let you express more complex use 
cases. It's one of the reasons I voted against the recent RFC to allow 
an extra reassignment of properties in the constructor 
[https://wiki.php.net/rfc/promoted_readonly_constructor_reassign].



--
Rowan Tommins
[IMSoP]


Re: [PHP-DEV] [RFC] Primary Constructors

2026-06-28 Thread Nick Sdot


On 29.06.26 08:17, Rob Landers wrote:

Hello internals,

I'd like to put forward Primary Constructors 
 for comment.


An implementation PR will be opened later today (UTC), and the RFC 
updated with this discussion thread.


— Rob



Hey Rob,

thanks again for the work you did put into this!

Unfortunately you are not allowing bodies for primary constructor. This 
means there will be no way to work around the "`readonly` classes don't 
allow property hooks" problematic; except using conventional 
constructors (`private(set)` is not the same; hence my previous 
"readonly hooks" RFC).


If "use conventional constructors, if you need `readonly` classes" 
stands, then the same can be argued for everything else in the RFC.


Why would we introduce a whole new syntax, but then only make it work 
for limited use-cases such as "trivial validation or normalization"?


Your example:

```

class Money(
public readonly int$amount,
public readonly string$currency = 'USD',
) {}

class Money{
public function __construct(
public readonly int$amount,
public readonly string$currency = 'USD',
) {}
}

```

Pro:
- two lines less
- construction at top of class (love it!)

Con:
- primary constructor body not supported
- new syntax with gotchas to keep in mind
- for readonly classes it adds two property `readonly` in exchange to 
writing two lines less
- requires refactoring to conventional constructor as soon as it gets 
"non-trivial" (I'd argue a lot of things that do not work are actually 
still trivial).


Given the limitations, is this alone adding enough value? What is the 
actual gain?


Adding a new syntax to the language but then lock it down as proposed 
here does not feel right.
As is, I feel the proposal is too thin, it would unfortunately be yet 
another feature that feels mid, incomplete, and introduces new gotchas.

Sorry, IMO, not worth it.

If we would say we want new and neat syntax sugar to write constructors 
at the top of the class, I am all for it!
But then they would need to work like actual constructors (otherwise 
it's not just sugar), without accepting yet another set of limitations 
and weirdness's in a different place.


What I roughly have in mind:

```
readonly class Point(public int $x, int $id = 0) extends Base($id) 
implements Foo {

   // normal constructor body behaviour
} => {
  // class body
}
```

--

Cheers
Nick