Re: [RFC] New in initializers

From: Date: Tue, 11 May 2021 14:41:41 +0000
Subject: Re: [RFC] New in initializers
References: 1 2 3 4 5 6 7 8 9 10  Groups: php.internals 
Request: Send a blank email to internals+get-114389@lists.php.net to get a copy of this message
On Tue, May 11, 2021, at 8:57 AM, Rowan Tommins wrote:
> On 11/05/2021 14:12, Dik Takken wrote:
> > So the use of "new" in initializers would require extending this base
> > class and call the parent constructor. Maybe forgetting to do so could
> > throw, preventing initializers from silently not working.
> 
> 
> If we managed to get that working, I wonder if we could also include a 
> check for uninitialized typed properties, a bit like Swift's "two-phase 
> initializers". In short, make this throw an error:
> 
> class Foo extends \PHP\Base {
>      private Logger $logger;
> 
>      public function __construct() {
>          parent::construct(); // "Error: Property $logger has no default 
> and was not initialized before calling Base constructor"
>      }
> }
> 
> This would catch bugs closer to their source, where currently there is 
> no error until $logger is accessed.
> 
> 
> However, the "if" at the beginning of this message is quite a big one: 
> it's not obvious where to assert any of this, because the constructor is 
> just called as a normal method *after* the engine considers the object 
> to be "created".

In practice, I almost always see the parent constructor called first, then the child constructor
does its own thing.  Having the language require you to do it backwards in order to use a new
feature would be... well, not technically a BC break per se, but certainly invalidating what is
currently standard practice.

If I'm following correctly, the concern is cases like this:

class Point {
  private Logger $logger = new FancyLogger();
  public function __construct(public int $x, public int $y) {
    $this->logger->log("Point made.");
  }
}

class FancyLogger {
    public function __construct() {
      $this->db = new DatabaseConnection();
      $this->db->write('Logger start.');
    }
}

$p1 = new Point(); // This writes "Logger start" then "Point made."

$p2 = unserialize(serialize($p1)); // This writes just "Logger start."

Am I understanding that right?  If so, I'm... unclear why that is any more of an issue than
doing it the manual way now.

--Larry Garfield


Thread (38 messages)

« previous php.internals (#114389) next »