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

Reply via email to