Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-16 Thread Rowan Collins

Kris Craig wrote on 16/02/2015 01:40:

 create the static instance

Isn't that essentially a contradiction in terms?  I can't help but 
feel that blurring the line between static and non-static 
classes/methods would cause more harm than good.


I've never really done any work with Redis before so I'm also having 
trouble understanding the use case for this given that everybody's 
talking about this solely in the context of Redis.


It's basically like any database connection - in a simple app, you just 
need a single connection that you can run lots of queries against, so 
global/singleton access is very convenient.


I do see the use case, but am not sure it's compelling enough to add a 
language feature, given that a similar effect can be achieved using 
existing features.


Regards,
--
Rowan Collins
[IMSoP]

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



Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Patrick Schaaf
Am 15.02.2015 21:05 schrieb Rowan Collins 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);

 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.

 ... 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.

 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. And the best to extend - I
just make another subclass.

Of course, there are places (in other classes) where stuff needs to use
such a redis instance without caring which one it is - i.e. an instances is
passed to a constructor there - in which case I can use the MyRedis::link()
method to get at the singleton instance.

But in most (I'd guess 90%) of the calling places, it's just the static
calls I need, and writing each of them as MyRedis::singleton()-xxx() is
more tedious.

best regards
  Patrick


Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread S.A.N
2015-02-15 21:04 GMT+02:00 Patrick Schaaf p...@bof.de:
 Hello Internals,

 seeing the static calling of instance methods being discussed again, I want
 to ask whether the following idea would maybe have a chance?

 In our codebase we have one set of classes where it was very useful to be
 able to call the same methods both statically and nonstatically: a set of
 wrapper classes over phpredis where subclasses know which set of redis
 servers to talk to (plus other config like retry strategies and timeouts).
 In most cases calling code does not need to be concerned with these details
 and just calls methods like red_global::get() or red_local::put().

 By neccessity the implementation of this class set, must make use of both
 __call() and __callStatic() magic methods, with both then dispatching to a
 delegate phpredis instance, and in the case of __callStatic(), making
 up-front a singleton like new self once. For a set of additional helper
 methods (not present on the underlying phpredis) I additionally have a
 special mapping array of real method names to internal implementation names.

 A similar approach can be useful for database connection abstraction
 classes.

 Now for the idea how this might be made much more simple: onviously in the
 light of the static call to method using $this warning/detection, PHP
 already knows exactly where it hits such a static call to an instance
 method. At that point, check whether the class has a static instance
 already. When it has one, call the method with $this being that static
 instance. Otherwise, create the static instance, calling a new magick
 method named __constructStatic() to initialize it. Only classes that have
 such a __constructStatic() method, would be treated that way. For other
 classes the static call to instance method case would be an error as
 before/discussed.

 This approach would clearly simplify my redis wrapper classes, maybe even
 enable them to be proper subclasses of phpredis (saving an indirection to a
 $this-delegate object). All the special dispatch and __callStatic
 instantiation logic could go away.

 The cost would be one internal pointer (to the static instance object)
 per class, a kind of hidden static protected property, and only needed
 when the class (or one of its superclasses) _has_ a __constructStatic
 method in the first place.

 What do you all think? Interesting? Somebody hot for helping with
 impementation? Then I'd make an RFC of it.

 best regards
   Patrick

+1

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



Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Rowan Collins

On 15/02/2015 19:04, Patrick Schaaf wrote:

In our codebase we have one set of classes where it was very useful to be
able to call the same methods both statically and nonstatically: a set of
wrapper classes over phpredis where subclasses know which set of redis
servers to talk to (plus other config like retry strategies and timeouts).
In most cases calling code does not need to be concerned with these details
and just calls methods like red_global::get() or red_local::put().

By neccessity the implementation of this class set, must make use of both
__call() and __callStatic() magic methods, with both then dispatching to a
delegate phpredis instance, and in the case of __callStatic(), making
up-front a singleton like new self once. For a set of additional helper
methods (not present on the underlying phpredis) I additionally have a
special mapping array of real method names to internal implementation names.


This sounds to me like you should just be using the Singleton pattern, 
at which point you need no magic calls at all. It can even be done as a 
subclass of an existing non-static class:


class MyRedis extends Redis {
private static $singleton;
public static function singleton() {
if ( is_null(self::$singleton) ) {
self::$singleton = new self; // may need parameters here
}
return self::$singleton;
}

// Other methods can go here, just like a normal subclass
}

// Now wherever in the code you want the default instance, just use this:
$value = MyRedis::singleton()-get($key);
MyRedis::singleton()-someCustomAction($anotherKey);

The nice thing about an explicit Singleton is you can migrate to 
Dependency Injection (call $redis = MyRedis::singleton() and start 
passing the instance around, until you get to the point where it is only 
called once), 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).


Making static calls implicitly access a singleton seems like it would 
make code harder to read, and harder to extend, in exchange for typing a 
few characters on each call (you could call it something shorter, like 
::inst() if you valued brevity) so a -1 from me.


Regards,

--
Rowan Collins
[IMSoP]


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



Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Rowan Collins

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



Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Rowan Collins

On 15/02/2015 19:04, Patrick Schaaf wrote:

By neccessity the implementation of this class set, must make use of both
__call() and __callStatic() magic methods, with both then dispatching to a
delegate phpredis instance, and in the case of __callStatic(), making
up-front a singleton like new self once. For a set of additional helper
methods (not present on the underlying phpredis) I additionally have a
special mapping array of real method names to internal implementation names.


A quick thought - if you want to stick with the magic static call 
pattern, you can implement this much more simply by doing something 
similar to Laravel's facades [1]:


class MyRedis extends Redis {
// extra instance methods here
}

class MyRedisFacade {
private static $instance;
public static function __callStatic($method, $params) {
if ( is_null(self::$instance) ) {
self::$instance = new MyRedis;
}
self::$instance-$method(...$params);
}
}


This basically implements in userspace what you propose to add to the 
language, with the only caveat being that you must separate the concerns 
of adding extra functionality, and wrapping it in a static facade, into 
two separate classes.


[1] http://laravel.com/docs/4.2/facades

--
Rowan Collins
[IMSoP]


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



Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Christoph Becker
Patrick Schaaf wrote:

 Am 15.02.2015 21:05 schrieb Rowan Collins rowan.coll...@gmail.com:
 
 // 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);

It's possible to add static methods or use __callStatic() to delegate to
the singleton's instance methods, though.

-- 
Christoph M. Becker


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



Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Kris Craig
 create the static instance

Isn't that essentially a contradiction in terms?  I can't help but feel
that blurring the line between static and non-static classes/methods would
cause more harm than good.

I've never really done any work with Redis before so I'm also having
trouble understanding the use case for this given that everybody's talking
about this solely in the context of Redis.

--Kris


Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Patrick Schaaf
Am 15.02.2015 23:34 schrieb Rowan Collins rowan.coll...@gmail.com:

 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.

Fair enough. You judge readabilidy by an unaccustomed reader can grasp
(better or worse) what lies behind this construct. I have a different
focus, as I'm just a herder of a small group of internal developers.

  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?

Without any caller side change, calling this already existing instance
method:

public function link() { return $this; }

 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:

Nothing would stop me from writing and using such a subclass, while having
fixed (in code) configuration sibling classes. Or add such a
fixed-config-singleton class method to the base class to add that to the
whole hierarchy. I don't have the need. But I could.

 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.

Or, in my case, s/MyRedis::/MyRedisReg::inst('volatile')-/g. Piece of cake.

 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.

Nothing of that. By base class is fully flexible! It even throws an
exception when a coder tries to singleton-like use it itself - it's just
the concrete subclasses that can be used that way.

I consciously chose this nonextensibility. Of course this is (for the given
fanout of different redis servers) nothing that a public facing library
would use! I'm watching over a four man coder show writing a single web
site's code not indented for public consumption. And there, such things not
only make sense, they happen all over the place.

Anyway, I'm pretty sure that singleton subclasses are useful in various
other one-of-a-few-specializations cases for completely different uses, and
there the patterrn might just make sense, too.

I certainly understand your criticism, from a point of view of more
publically consumable codebases / libraries. Thanks for your feedback.

best regards
  Patrick


Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Patrick Schaaf
Am 16.02.2015 02:40 schrieb Kris Craig kris.cr...@gmail.com:

 I've never really done any work with Redis before so I'm also having
trouble understanding the use case for this given that everybody's talking
about this solely in the context of Redis.

Ahem, it's not everbody, just me :) And the issue comes up in the context
of redis because persistent connection without keeping around yet another
global $myglobalredis, and
ease of use to me in that concrete case. Yeah. I had a use case. That's
all. I'll rest my case soon if there are no others.

best regards
  Patrick


Re: [PHP-DEV] A modest proposal: __contructStatic

2015-02-15 Thread Patrick Schaaf
Am 16.02.2015 00:05 schrieb Rowan Collins rowan.coll...@gmail.com:

 A quick thought - if you want to stick with the magic static call
pattern, you can implement this much more simply by doing something similar
to Laravel's facades [1]:
...
 This basically implements in userspace what you propose to add to the
language, with the only caveat being that you must separate the concerns of
adding extra functionality, and wrapping it in a static facade, into two
separate classes.

That was one of my intermediate steps before reaching the current approach,
but it irked me that when switching code from MyRedis static/singleton
usage to real instance usage I suddenly have to write a different class. In
my scheme, where I can use red_global::get() I can as well use $redis = new
red_global(); $redis-get(); without thinking about how that companion
class was named.

Sure, no big issue. But a small one... By itself, surely not enough reason
for a language change :)
It's all a question of how many other small such uses there would be.

best regards
  Patrick