Hi Rowan, hi all! Le ven. 17 mars 2023 à 15:51, Larry Garfield <la...@garfieldtech.com> a écrit :
> 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. :-) > I created this draft RFC to help move things forward: https://wiki.php.net/rfc/syntax-to-capture-variables-when-declaring-anonymous-classes Please let me know your early thoughts and I'd be happy to move it to "under discussion". I'd also need someone for the implementation as I doubt I'll be able to write it myself in a reasonable time! Cheers, Nicolas