[dev] Horde_Session thoughts

Michael M Slusarz slusarz at horde.org
Tue Nov 2 06:03:49 UTC 2010


Quoting Jan Schneider <jan at horde.org>:

> Zitat von Michael M Slusarz <slusarz at horde.org>:
>
>> Quoting Jan Schneider <jan at horde.org>:
>>
>>> Zitat von Michael M Slusarz <slusarz at horde.org>:
>>>
>>>>  Allow ability to search session subkeys.
>>>>
>>>>  We store values with key & subkey together to save on  
>>>> storage/serialization
>>>>  costs. To retrieve array like output, simply need to call
>>>>  $session['app:name/'] - returns an array with subkeys as keys and session
>>>>  values as values.
>>>
>>> This sounds like a bit too much magic for a small performance  
>>> gain. I'd rather like this to be a real array for  
>>> readability/maintainability, and loose a bit of performance. Can't  
>>> be too much anyway.
>>
>> Disagree.  I personally am finding that storing something with a  
>> session index like:
>> ['imp:imp_mailbox/INBOX']
>> is *much* clearer (since all the pertinent information is in the  
>> same string and not separated by PHP-ish cruft) in the code than:
>> ['imp']['imp_mailbox']['INBOX']
>> not to mention easier to write and less prone to typos/errors.
>>
>> Especially since I have only found *1* instance in the code so far  
>> where we were actually using the iterative/collective property of  
>> arrays (the horde:auth_app variable).  In every other instance, we  
>> are carrying around the overhead of an array data structure solely  
>> for the fact that it might make things a bit clearer in the code -  
>> but, as I argue above, that is not true anymore either.
>>
>> But nothing I have added will prevent anybody from storing arrays  
>> if they want.
>
> I feel rather strong about this being counter-intuitive. Any other  
> opinions about this?

My (belated) take on this...

I have very strong feelings that the way I have implemented is *much*  
preferable - and these opinions are because I have spent 5+ hours  
converting things and tweaking the API syntax to make things as easy  
as possible to both code, read, and debug.  But I need to pick my  
battles and since everyone else seems to be against it, I'm going to  
concede this issue for now.

Well... only somewhat concede because there have been several other  
comments about implementation changes that are DEFINITELY not  
happening.  Hopefully I touch on all points below

1. API

The API must be as follows:
$horde_session->get($app, $name[, $options_mask])
$horde_session->set($app, $name, $value[, $options_mask])
$horde_session->remove($app, $name)

Writing this out, it is painfully apparent how much cleaner the array  
syntax is.  E.g.,
$horde_session['app:foo'] = $value;
vs.
$horde_session->set('app', 'foo', $value);
But I digress...

Most important, and this goes for classes/objects other than  
Horde_Session, you absolutely CAN NOT USE MAGIC PROPERTY ACCESS  
METHODS (i.e. $horde_session->variable name).  First, in the  
Horde_Session case, it can't be used since session data is not a  
simple key->value lookup.  It is stored by app name.  You could  
theoretically do fancy manipulation by stacking objects on top of  
objects, (i.e. $horde_session->horde->variable_name) but what's the  
point besides adding a bunch of unneeded complexity?  And you can't  
pass options using this syntax.

Most important, using magic properties is simply a terrible design  
decision for data objects where the key name is entirely dynamic, for  
the obvious reason that the possible keys are limited.  This was  
precisely why I used array access in the first place - to prevent this  
limitation.  The only time using __get() makes sense for dynamic  
property accesses is when the keys are already defined and limited  
(see, e.g., IMP_Mailbox_Element - property access makes sense here to  
prevent us from having to write 30 mini-methods of 1-2 lines each to  
return a dynamic value).

This is precisely why I added an array access possibility to  
Horde_Prefs, but there can not be a parallel object property access API.

2. Storage in the session needs to be as flat as possible.

Don't have the link in front of me, but read somewhere recently that a  
PHP array with a single element requires 300+ bytes (as opposed to  
something like 68 bytes for a scalar value).  So deep arrays need to  
be avoided at all costs.

Through my process of converting so far, my conclusion is that there  
is absolutely no reason that 99% of session variables need to be  
living in an array format.  The vast majority of session variables are  
scalar values and don't need to be living in an array.

Debugging is not a valid argument against this.  If we need a way to  
pretty print the current session, it is trivial to add a debug method  
to Horde_Session.

And this argument is moot anyway, since actual storage format can be  
easily changed in the future once all session reading/writing is  
filtered through Horde_Session.

This leads to...

3. For technical reasons, DIRECT ARRAY ELEMENT ACCESS ISN'T POSSIBLE ANYWAY

This is no longer possible:
$_SESSION['app']['foo']['bar']['enabled'] = 1;

Nothing you can do about it.  This MUST be done this way (with the  
proposed API from above):
$a = $horde_session->get('app', 'foo');
$a['bar']['enabled'] = 1;
$horde_session->set('app', 'foo', $a);

This is a technical limitation due to the fact that we need to track  
if a session element has been altered in order to determine if we need  
to update the session data on shutdown.  Right now we use md5()  
checksums to do this check, but the new method is magnitudes faster  
(just like using md5 checksums is magnitudes faster than writing to  
the session storage backend on every pageload, even if session data  
doesn't change).

As a compromise to limiting array access, this is why I added...

4. The *EXTREMELY* useful 'varname/subname' format

There are certain situations where it is useful to allow at least a  
basic key->value lookup for certain data items.  For example, the  
authentication data stored in horde.  It is much clearer code to store  
things as 'auth/appname' than creating a bunch of individual keys like  
'auth-appname'.  More important, it gives us the ability to later be  
able to work with these data elements as a whole - like if we wanted  
to reset all authentication tokens at once.  Thus the need for a  
shorthand format to allow us to do this.

I really don't see how this is "counter-intuitive".  If you don't like  
this feature, don't use it.  It doesn't affect anything else, while  
providing shortcuts to allow iteration and easy removal.

I will reserve comment on removing our Horde globals for another time  
other to see I _deeply_ disagree with that decision.  I have  
absolutely no problem with providing a small number (for us it is 10  
or less) of globally available variables for items that are  
universally used.  These globals are available only to applications.   
Asking an application developer to start to have to inject EVERYTHING  
into a page seems to be a GIANT step backwards in terms of making the  
framework easier to use.  There is absolutely nothing wrong with  
providing intelligent shortcuts to make coding easier.  This idea  
seems more like a quest for perfect OO-coding purity than a decision  
to make actual coding better.

I will start work on moving converted code to the new API.

michael

-- 
___________________________________
Michael Slusarz [slusarz at horde.org]



More information about the dev mailing list