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