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