Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:82759 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 29570 invoked from network); 15 Feb 2015 22:33:35 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 15 Feb 2015 22:33:35 -0000 Authentication-Results: pb1.pair.com header.from=rowan.collins@gmail.com; sender-id=pass Authentication-Results: pb1.pair.com smtp.mail=rowan.collins@gmail.com; spf=pass; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 74.125.82.180 as permitted sender) X-PHP-List-Original-Sender: rowan.collins@gmail.com X-Host-Fingerprint: 74.125.82.180 mail-we0-f180.google.com Received: from [74.125.82.180] ([74.125.82.180:50448] helo=mail-we0-f180.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id E2/52-13857-CBE11E45 for ; Sun, 15 Feb 2015 17:33:34 -0500 Received: by mail-we0-f180.google.com with SMTP id k11so26119682wes.11 for ; Sun, 15 Feb 2015 14:33:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type:content-transfer-encoding; bh=5oP7ttqixw8PaLez0GJTJALNF3Gl0GWpbZ8H0LYVrFk=; b=iiiVMDyrsCsBkWGY8rk4/B0W9vC8jaKWOn51VXkbgIugERe6Ecy4wTe/rBe/+KyvxL CeP9po+RZ5cMv58rPpHlxAD9CtpFmG4gxf8IA2yT+RehN2GjFD0KV4bbRhAsywase9wW 8Ow2th5vGhY3LnRzUeFGbSsRRJ3GfcB9E9LEmZhQIy/HlOF25pE8gq+amyEMjrc+oBoS MYEfIO/5jBJSTIdECqKZas1eXMug2nAa7z7OH2bNAfwNUKsNVhF2khhojHEFrEwMc1OI RoJ4/GNz9RldTq4l+AOxH5Trgy4lbys2FetM8VDv81Kvj6YIPzje7KVnmKmdz2ZMLh4f qmsw== X-Received: by 10.194.83.66 with SMTP id o2mr31088600wjy.55.1424039609622; Sun, 15 Feb 2015 14:33:29 -0800 (PST) Received: from [192.168.0.2] (cpc68956-brig15-2-0-cust215.3-3.cable.virginm.net. [82.6.24.216]) by mx.google.com with ESMTPSA id n2sm16889218wiw.16.2015.02.15.14.33.28 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 15 Feb 2015 14:33:28 -0800 (PST) Message-ID: <54E11EAA.7000004@gmail.com> Date: Sun, 15 Feb 2015 22:33:14 +0000 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: internals References: <54E0FBE0.10301@gmail.com> In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [PHP-DEV] A modest proposal: __contructStatic From: rowan.collins@gmail.com (Rowan Collins) On 15/02/2015 20:20, Patrick Schaaf wrote: > > > Am 15.02.2015 21:05 schrieb "Rowan Collins" >: > > > > This sounds to me like you should just be using the Singleton pattern, > > Of course this is singleton under the hood. > > > // Now wherever in the code you want the default instance, just use this: > > $value = MyRedis::singleton()->get($key); > > You can surely see how this is more readable / easier to write: > > $value = MyRedir::get($key); > Actually, no, I find that harder to read accurately - there is no clue there that there is actually a singleton under the hood, and that this is actually an instance method in disguise. For writing, it saves, in this case, 13 characters; change the method name to inst(), and that difference goes down to 8 characters. And if you use it lots of times in succession, you wouldn't even need to call the accessor every time: $redis = MyRedis::inst(); $foo = $redis->get('foo'); $bar = $redis->get('bar'); // etc In that scenario, you've had to write one extra line at the top of the method, and the rest of the lines are probably shorter (if the variable name is more than one character shorter than the class name). Plus, you have the bonus of being able to use an injected connection later. > > The nice thing about an explicit Singleton is you can migrate to Dependency Injection (call "$redis = > MyRedis::singleton()" and start passing the instance around, > > I _can_ do that with my redis class, where I need it, by calling a > method MyRedis::link() which just returns $this. But the places where > I need that are rare. > You may be able to do it with your current implementation, but how do you propose to do it with an invisible singleton property implicitly created by __constructStatic? > > ... or to a cleverer factory / service locator (store more than one instance in different static variables or a > keyed array, to connect to different stores for different purposes). > > This i do with subclasses, where the subclass define suitable static > protected properties that guide the connect logic (which sits in the > baseclass). I have a global redis, a local redis (local to the host > the code runs on), a volatile redis (global, but does not make > prersistent dumps), and so on. Calling code ready red_global::this(), > red_volatile::that(), and so on. You don't get it better readable (and > greppable) as that. > OK, but you need a new subclass every time, not just a new method, or new parameter; that limits your options. For instance, you can't dynamically create instances based on configuration of a reusable library, which could be as simple as adding an optional parameter to a standard Singleton: class MyRedis { private static $instances; public static function inst($type='default') { global $config; if ( ! array_key_exists(self::$instances, $type) ) { self::$instances[$type] = new self(...$config['redis_options'][$type]); } return self::$instances[$type]; } } Any function that already uses the "$redis = MyRedis::inst();" pattern can then quickly be changed to "$redis = MyRedis::inst('volatile');" and continue to work fine. > > Making static calls implicitly access a singleton seems like it would make code harder to read, and harder to > extend, > > I don't understand. It's the best to read to me. > OK, we'll call that one a matter of opinion. > And the best to extend - I just make another subclass. > "Extend" was perhaps not the word I should have chosen; I was thinking of "extending the use of the class beyond the current coding pattern". By implementing one specific use case as a magic method, you make it harder to do anything other than that one use case; or, you end up creating a whole set of magic methods and features, which are then no easier than just implementing the whole thing by hand. I deliberately didn't go into details of the arguments against the Singleton pattern in general in my last e-mail, because I was comparing your "magic" code to a normal Singleton. However, those criticisms are out there, and adding a feature to the language specifically in order to support Singletons, in a very limited way, will be considered by some as encouraging bad practice. Regards, -- Rowan Collins [IMSoP]