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