Page 1 of 1

Session object wrapper

Posted: Wed Oct 17, 2007 12:45 am
by alex.barylski
A while back I had a breif disscussion with d11 about REQUEST objects and I used his thoughts/advice when considering whether I should refactor my global GPC code into a more plesant REQUEST object. Although I do not disagree that it certainly feels more right, that simply didn't offer enough advantage for me to bother refactoring the GPC variables - at this time.

Fast forward. Today, I was working with sessions and I stopped to think about their use...and more importantly ask myself, should I use a simple SESSION wrapper and perhaps design it in such a way it allowed for data storage abstraction (so I can use RDBMS, etc instead of default session storage).

I am still considering it, but I would like to ask:

Does anyone use a trivial SESSION wrapper to add namespace protection and maybe an abstraction layer for data storage???

Can you provide an example?

Do you consider this separate from REQUEST or REGISTRY objects?

Cheers :)

Posted: Wed Oct 17, 2007 1:25 am
by Kieran Huggins
I don't think you need a wrapper class for handling sessions. Check out session_set_save_handler()

You might also consider using a HEAP table, at least for sessions that are less than 30 minutes old. Long term session storage could be moved to a ISAM table if you're concerned about running out of memory. The number of minutes would obviously be adjusted based on server load, etc...

There's a tutorial on this at devshed, but I can't personally vouch for it. I'm sure you'd have no trouble coming up with your own, but it never hurts to have an example :)

Posted: Wed Oct 17, 2007 3:11 am
by Maugrim_The_Reaper
The problem with Sessions is where they're used. They can be used by any number of objects, across any number of components, across any number of applications. So my main concerns are:

1. Namespaces
2. Storage method
3. Access style (ArrayAccess/OO)

What I really like is to have classes which accept a Session object implementing ArrayAccess from SPL. So it acts like a normal array (which is good for BC) but is actually an object. More interesting, each object does not represent the entire $_SESSION - only a specific sub-array (or namespace) so conflicts are more difficult since older namespacing isn't affected, and can't touch the top-level $_SESSION anymore ;). A core Session object held by the namespaced session object can mediate to the storage medium using whatever your preferred strategy (file, MEMORY table or other database) may be, and track each namespace. It should throw some kind of exception if a new Session object with a conflicting namespace is created - allowing overwriting by default probably isn't a good idea.

Why is a wrapper class useful? It acts like an Array and solves the bane of all things global - namespacing, and abstracted storage. The only problem is whether other code will let you hook in a custom Session object or array without making changes. I'd have to say you'd mostly need changes since few consider you wanting to specifically plant a replacement for $_SESSION. Most code will reference it directly - which is a big problem since it breaks enough OO rules to make changing this a messy task.

Posted: Wed Oct 17, 2007 4:03 am
by Kieran Huggins
Would there not be some sort of problem due to the fact that session saving occurs during the shutdown of the script? It's my understanding that all objects are destroyed before this happens.

Posted: Wed Oct 17, 2007 6:31 am
by alex.barylski
Thanks for the reply guys.

Essentially, I really like the idea of datastorage abstraction, but using normal session storage if desired. Also there is the added benefit of namespacing and just making the code look more OOP in style.

I actually plan on using SESSION for two similar but distinct uses - so I think separate objects would help in clarifying which is which rather than storing everything in a single SESSION variable.

Basically I plan on having Application state (authenticated flag, etc) and Page state (listings, etc) - hence the namespace requirement. I have to spend some more time investigating the practicality behind the latter but it should simply my overall code if things go according to plan.

Posted: Wed Oct 17, 2007 9:08 am
by Maugrim_The_Reaper
Would there not be some sort of problem due to the fact that session saving occurs during the shutdown of the script? It's my understanding that all objects are destroyed before this happens.
True, but the objects are sitting on top of $_SESSION. We're just adding an OO API on top of the existing superglobal using Namespace tracking to prevent subarray naming conflicts.

The savehandler is a separate set of classes (or functions if preferred) implemented in whatever way seems appropriate. You could also add an object destructor to the handler to manually write the session closed - pretty sure that was added around PHP5.1 to get around the timing messup.

Edit: Nope, pre 5.1 - session_write_close()

Re: Session object wrapper

Posted: Thu May 14, 2009 3:09 pm
by ornerybits
I know the prev post is a little old, but here's something I implemented that is similar to the descriptions above. It is not technically namespace-safe, but with my implementation, I've found it to be convenient to have the top-down union of all 'SessionSpaces'

Code: Select all

 
<?php
define('SESSION_PATH_DELIM', '/');
 
class SessionSpace implements ArrayAccess{
 
    protected $path;
    protected $space;
    
    public function __construct($path=null, $clear=false){
        if ($path !== null) $this->init($path, $clear);
    }   
    
    /** 
    * init Initializes the session space.
    * @param string $path String of array keys (delimited by SESSION_PATH_DELIM) that defines where the session space should live within the session.
    * @param boolean $clear If true, will reinitialize session data to empty arrays at all points along the path. If false, will leave any existing session
    *   data untouched.
    */
    public function init($path, $clear=false){
        if (is_string($path)){
            $this->path = $path;
        }   
        else {
            throw new Exception('First argument to SessionSpace::init() must be a string.');
        }   
 
        $path_parts = explode(SESSION_PATH_DELIM, $this->path);
        $_session_ref =& $_SESSION;
 
        foreach($path_parts as $path_part){
            if (!is_array($_session_ref[$path_part]) || $clear){
                $_session_ref[$path_part] = array();
            }   
            $_session_ref =& $_session_ref[$path_part];
        }   
        $this->space =& $_session_ref;
    }   
 
    // ArrayAccess methods
    public function offsetGet($var) {
        return $this->space[$var];
    }   
 
    public function offsetSet($var, $value) {
        $this->space[$var] = $value;
    }   
 
    public function offsetExists($field_name) {
        return isset($this->space[$field_name]);
    }
 
    public function offsetUnset($field_name) {
        unset($this->space[$field_name]);
    }
}
?>
 
So... I can now do things like this:

Code: Select all

 
$parentSession = new SessionSpace('parent');
// equivalent to:  $_SESSION['parent'] = array();
 
$parentSession['name'] = 'Gary Busey';
// equivalent to: $_SESSION['parent']['name'] = 'Gary Busey';
 
$childSession = new SessionSpace('parent/child');
// equivalent to: $_SESSION['parent']['child'] = array();
 
$childSession['name'] = 'Jake Busey';
// equivalent to: $_SESSION['parent']['child']['name'] = 'Jake Busey';
 
$grandchildSession = new SessionSpace('parent/child/grandchild');
// equivalent to: $_SESSION['parent']['child']['grandchild'] = array();
 
$grandchildSession['name'] = 'Not born yet that i know of';
// equivalent to: $_SESSION['parent']['child']['grandchild']['name'] = 'Not born yet that i know of';
 
echo $parentSession['child'][''name'];
// will output 'Jake Busey'
 
echo $childSession['grandchild']['name'];
// will output 'Not born yet that i know of'
 
 
 
 
So you see we have a nice top-down union of 'Session Spaces'. You certainly can still have namespace conflicts, so you must be careful not to overwrite. Right now I've had no problems in my implementation, but checking for and raising exception in the case of conflicts would be nice.

Re: Session object wrapper

Posted: Fri May 15, 2009 11:58 am
by John Cartwright
FYI, your offsetExists() and offsetUnset() are not referencing the field name.

Re: Session object wrapper

Posted: Thu Jun 04, 2009 10:42 am
by ornerybits
thanks John, fixed it above