Session object wrapper

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Session object wrapper

Post 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 :)
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post 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 :)
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post 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.
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post 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.
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post 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.
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post 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()
User avatar
ornerybits
Forum Newbie
Posts: 18
Joined: Thu May 14, 2009 2:08 pm
Location: Kansas

Re: Session object wrapper

Post 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.
Last edited by ornerybits on Thu Jun 04, 2009 10:41 am, edited 2 times in total.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Re: Session object wrapper

Post by John Cartwright »

FYI, your offsetExists() and offsetUnset() are not referencing the field name.
User avatar
ornerybits
Forum Newbie
Posts: 18
Joined: Thu May 14, 2009 2:08 pm
Location: Kansas

Re: Session object wrapper

Post by ornerybits »

thanks John, fixed it above
Post Reply