Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:97733 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 31406 invoked from network); 12 Jan 2017 21:14:11 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 12 Jan 2017 21:14:11 -0000 Authentication-Results: pb1.pair.com header.from=ocramius@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=ocramius@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 74.125.82.41 as permitted sender) X-PHP-List-Original-Sender: ocramius@gmail.com X-Host-Fingerprint: 74.125.82.41 mail-wm0-f41.google.com Received: from [74.125.82.41] ([74.125.82.41:36919] helo=mail-wm0-f41.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 5D/7A-50165-1A1F7785 for ; Thu, 12 Jan 2017 16:14:10 -0500 Received: by mail-wm0-f41.google.com with SMTP id c206so40656590wme.0 for ; Thu, 12 Jan 2017 13:14:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=VUJqHzZzJ9HS9r9nYMFVwaiUR1iTag2UDV8SElInabc=; b=Gn4hn1gxra/TuAmiAUTQ37iuxGoqqBfe/kb0RaRgydyKLtFib9GQglhG5yonkqqbxH wuSMNheCYWYxTa11BGk1W9pA6b8fwbEXxj7cd2lUyUsp65cKD6OrDF++s5VaXTsTv6vn 8iky1ElMQgN0DzaeJeWA6kbVGt8A9ezQm4aswF0rHjEYKVk9rGT848bHrLVUnXqJq9ql 2FEgw/HUCMraQui7o/tcX2Gq+O+uM2WlCy9MHeE+lKNfML0ldOYOP6GBxe9UmNnL+csJ O9shwWljjocvbm+EICt1eyPFnIHpSUwtO6+jbMPvbQ3FgD4Q8r9Y4iZdNbMnAcQDlmBt 6/yg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=VUJqHzZzJ9HS9r9nYMFVwaiUR1iTag2UDV8SElInabc=; b=M+U8pXvq9P71vEB8y95KtnG6DO4NZ/IIh2zJttGoJwhSciy6px0XQ1F+6y4PANQ2TY dQPT+yuWQ2smq361rYPjHVz1V0VyFshEeiiIeIQFOO0cycdL/Hxz8FQiVtKMzRzahVvR 3J8G5F+nb+1Mtbfj18fur5vDldyJWJGDbh7SZinbgOTsfVr91vT/P4QEzoyE6RVXOgXJ zQUYva3QneW98uKPq2XAvmrWIuS1YQG1Zc4df1MGT3UzAXLS2NJQjVd4K99ESDsmFvcS fieKqZCwjnmpsVBpES2T5+Pcla04MX79FDDs9w2mYwFrhM6mXA4ghrkJ5rFAwQbxdUCH mW6A== X-Gm-Message-State: AIkVDXIFoZnTpDejDkJn+rl6UqndL87QbKpQgWjsYJC5PCIMcF6VZwQ24yH858/KYRsKukjx70pJCMmVWBtgLw== X-Received: by 10.28.157.200 with SMTP id g191mr64660wme.63.1484255646791; Thu, 12 Jan 2017 13:14:06 -0800 (PST) MIME-Version: 1.0 Received: by 10.194.34.197 with HTTP; Thu, 12 Jan 2017 13:13:46 -0800 (PST) In-Reply-To: References: <0DE25BF8-D349-48EF-A83B-8837DD4AD1E0@gmail.com> Date: Thu, 12 Jan 2017 22:13:46 +0100 Message-ID: To: PHP Internals List Cc: Tim Bezhashvyly Content-Type: multipart/alternative; boundary=001a114b41cc953efd0545ec3202 Subject: Re: [PHP-DEV] Explicit constructor call and polymorphic dispatch From: ocramius@gmail.com (Marco Pivetta) --001a114b41cc953efd0545ec3202 Content-Type: text/plain; charset=UTF-8 Hey Richard, On Thu, Jan 12, 2017 at 9:58 PM, Fleshgrinder wrote: > 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: > > > 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? > > ``` > > 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 > I made an example where everything was in a single class, but most scenarios involve a lazy-loading wrapper that has no knowledge of the original class besides its constructor. I use this approach to generate proxy classes that are "safe" to use with fluent interfaces, for example (because fluent interfaces are really a mess to work with). The alternative (for me, specifically) is to copy the constructor AST into a closure, then store the closure somewhere. Still, if that closure also calls the private constructor, I have to do it recursively, and so on until I just give up :-P Also, this assumes codegen. Large pieces of code will need rewriting, whereas I don't see strong reasoning for dropping a feature that, while weird, is actually useful. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/ --001a114b41cc953efd0545ec3202--