On Thu, Mar 16, 2023, at 6:05 PM, Rowan Tommins wrote:
> On 16/03/2023 22:14, Larry Garfield wrote:
>> Wouldn't the functionality described boil down to essentially just 
>> materializing into a few extra lines in the constructor?  At least to my 
>> ignorant non-engine brain it seems straightforward to have this:
>>
>> $a = 1;
>> $b = 2;
>> $c = 3;
>>
>> $o = new class ($a, $b) use ($c) {
>>    public function __construct(private int $a, private int $b) {}
>>    public function something() {}
>> }
>>
>> Desugar to this:
>>
>> $c = class ($a, $b) use ($c) {
>>    private $c;
>>    public function __construct(private int $a, private int $b) {
>>      $this->c = 3;  // By value only, so this should be fine?
>>    }
>>    public function something() {}
>> }
>
>
> Not quite - as Ilija pointed out, the class definition gets compiled 
> once, but the capture needs to happen for every instance, with 
> (potentially) different values of $c. In other words, $c needs to be 
> injected as a constructor argument, not a constant in the class definition.
>
> That's still fine, in principle - you can compile to this:
>
> $o = class ($a, $b, $c) {
>    public function __construct(private int $a, private int $b, private $c) {
>    }
>    public function something() {}
> }
>
> Or once constructor promotion is de-sugared as well, this:
>
> $o = class ($a, $b, $c) {
>    private int $a;
>    private int $b;
>    private $c;
>
>    public function __construct($a, $b, $c) {
>       $this->a = $a; // from constructor promotion
>       $this->b = $b; // from constructor promotion
>       $this->c = $c; // from use() statement
>       // other lines from body of constructor go here
>    }
>    public function something() {}
> }
>
>
> It just introduces a lot of extra cases to handle:
>
> * If there's no constructor, create one
> * If there is a constructor with other arguments, merge the argument 
> lists; since there will then be an explicit argument list to "new 
> class()", merge those lists as well
> * Maybe different handling if those other arguments are already using 
> constructor promotion, as in this example
> * If there are existing lines in the constructor body, combine those 
> with the auto-generated assignments
>
>
> Which is why I'm thinking a first implementation would be reasonable 
> which just took this approach:
>
> * "new class" can either have an argument list or a use() statement, not 
> both
> * the use() statement generates a constructor at the top of the class
> * if the class body already contains a constructor, the compiler will 
> complain that you have two methods named "__construct"

Ah, fair enough.  I'd want to see a better error message than that (which would 
be confusing for people who don't know what they're looking for), but otherwise 
that's a reasonable first iteration.  Especially as I can't recall when I last 
had an anon class constructor that was doing anything other than manual 
closures. :-)

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to