On 1/12/2017 9:35 PM, Marco Pivetta wrote:
> Heya,
> 
> While I agree that it is weird to be able to call constructors more than
> once, this is generally used for:
> 
>  * lazy loading
>  * resource reset
> 
> Specifically, what is going on is something like following:<?php
> 
> final class DbConnection
> {
>     private $dsn;
>     private $initializer;
>     public function __construct(string $dsn)
>     {
>         $this->dsn = $dsn;
>         // socket stuff happens here, much like with PDO
>     }
> 
>     public function query(string $queryString) : array
>     {
>         ($this->initializer)();
>         // irrelevant from here on
>         return ['query' => $queryString, 'dsn' => $this->dsn];
>     }
> 
>     public static function lazyInstance(string $dsn) : self
>     {
>         $instance = (new
> ReflectionClass(self::class))->newInstanceWithoutConstructor();
>         $instance->initializer = function () use ($dsn, $instance) {
>             $instance->__construct($dsn);
>             $instance->initializer = function () {
>             };
>         };
>         return $instance;
>     }
> }
> 
> $instance = DbConnection::lazyInstance('mysql://something');
> 
> var_dump($instance);
> 
> var_dump($instance->query('SELECT * FROM foo'));
> var_dump($instance->query('SELECT * FROM bar'));
> 
> Here's an example of it at work: https://3v4l.org/Y0eoL
> 
> The pattern is simple:
> 
>  * intercept constructor call
>  * capture constructor parameters
>  * instantiate without constructor
>  * defer constructor call for later
> 
> The same can be used in a myriad of different ways, but this is a legit
> use-cases that generally don't involve coding everything into the same
> class (and I generally advise against doing that anyway).
> 
> Therefore I don't see a reason to drop manual constructor calls, unless
> there is a strong necessity to get rid of 'em.
> 
> 
> 
> Marco Pivetta
> 

Very creative but why not the following?

```
<?php

final class DbConnection {

  private $dsn;

  private $initialized = false;

  public function __construct($dsn) {
    $this->dsn = $dsn;
  }

  private function init() {
    $this->initialized = true;

    echo $this->dsn , "\n";
  }

  public function query($queryString) {
    // this is actually cheaper than calling the closure
    $this->initialized || $this->init();

    return ['query' => $queryString, 'dsn' => $this->dsn];
  }

}

$db_conn = new DbConnection('mysql://something');

var_dump(
  $db_conn,
  $db_conn->query('SELECT * FROM foo'),
  $db_conn->query('SELECT * FROM bar')
);
```

https://3v4l.org/PaqqZ

Works equally well in PHP and HHVM and achieves your goal without using
undocumented side effects and reflection.

Adding the ability of a non-lazy and lazy construction is easily added
too if desired.

-- 
Richard "Fleshgrinder" Fussenegger

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

Reply via email to