On 15/02/2015 20:20, Patrick Schaaf wrote:
Am 15.02.2015 21:05 schrieb "Rowan Collins" <rowan.coll...@gmail.com
<mailto:rowan.coll...@gmail.com>>:
>
> 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]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php