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"


Regards,

--
Rowan Tommins
[IMSoP]

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

Reply via email to