tags:

views:

137

answers:

5

I have a session class that basicly just sets and retrieves session variables, the reason I made it was so I could easily change it to use sessions or something like memcache to set the items and have them accessible on multiple pages without hitting the database

I then have this user class which uses the session object to get session variables in it.
I am wanting to add to this user class though, to make it more encapsulated I would like to be able to set the variables that I am retrieving in this class so right now I can display the userid with $user->userid; I would like to first have a method or something that sets its value from the session object I guess Does this sound lke a good idea or possibly a lot of overhead?

And if what I am trying to do is a good idea maybe you could suggest/show example of how I should do it? I am thinking that if I add that method in that possibly I should move the code in the __construct method into it's own method

Basicly, I have the variables listed in the top part of the class that are used in the construct method, if I have multiple methods in the class though would I need to set them all at the top like that?

<?PHP
//user.class.php file
class User
{
    public $userid;
    public $name;
    public $pic_url;
    public $gender;
    public $user_role;
    public $location_lat;
    public $location_long;
    public $newuser;

    function __construct()
    {
     global $session;
     if($session->get('auto_id') != ''){
      //set user vars on every page load
      $this->userid = $session->get('auto_id'); //user id number
      $this->name = $session->get('disp_name');
      $this->pic_url = $session->get('pic_url');
      $this->gender = $session->get('gender');
      $this->user_role = $session->get('user_role');
      $this->location_lat = $session->get('lat');
      $this->location_long = $session->get('long');
      $this->newuser = $session->get('newregister');
     }else{
      return false;
     }
    }
}

//with the class above I can easily show some user variables I have saved into a session like this below
$user = new user();
$user->userid;

?>
A: 

I would set a new session with a name like "ValuesInSession" to true or false depending on whether or not you have session values for the fields in your user class. Then, in the sessions\users class you can check whether this session is true or false and set your values accordingly (IE from the existing sessions or to empty strings\0)

EDIT: You could, alternatively to putting that code in the user or sessions class, write a new class which could work with your users class to set the values properly (perhaps it could extend the sessions class?)

+1  A: 

I guess this is vaguely an answer to the "is this a good idea" question. In my understanding, locating variables in the session versus refreshing them from the database is a question of the trade off between complex queries and deserializing data. The session data isn't a free magic cache that escapes database calls, it is just a convenient wrapper around a database call that you don't have to deal with. Any variable that you place in the session must be serializable. The whole collection of serialized data is then managed; the server fetches the data using the session key, deserializes it all, and hands it to the php script. Then when it closes the session for that request-response cycle it serializes it all and puts it back in the db.

So the mess in dealing with all that can, in some cases, be worse than the mess of just opening a connection and asking the db for the same stuff (or a subset of stuff) directly.

I would say that putting one or two key values in the session is a good stopping place, and relying on it too heavily for statefulness is a less-optimal plan.

Mikeb
+1  A: 

In general your idea is a good one 3 things I would do differently:

1) In your implementation doesn't seem to consider having several users. ie Several instances of the same class.

2) I would use factories instead of using IF in the constructor. So for a user you have saved in the session you would call:

 $savedUser = User::fromSession($userId);

for a new user

  $user = new User()

3) Use the seralize and unserialze functions to save that data to the session

Then your class could could be implemented as

public static function fromSession($userId) {
   return unserialize($session->get('users_'.$userId));
}

public function save() {
   return $session->set('users_'.$this->id , serialize($this));
}
elviejo
The only adjustment I would make is to move `fromSession` and `save` into their own class (even better - interface) to make testing a bit easier. Let `User` handle user data stuff, let something else handle saving/serializing/retrieving/creating
rojoca
Thanks for the examples, I am curious, why serialize and unserialize the session stuff, currently I use sessions without doing that and they work fine so if there any benefit of doing it? what I mean basicly is $_SESSION['userid'] is available anywhere without serializng it or unserializing?
jasondavis
The adavantage is that it will serialize all the properties of the object in one step.So you don't need to get $_SESSION['userid'], $_SESSION['username'], etc.
elviejo
A: 

I'm not sure I understand the question, however, if you are using php 5, you can use the __set magic method to help with this.

Modifying your current class:

class User
{
     private $id;
     private $data = array();

     public function __construct()
     {
          global $session;
          $this->id = $session->get('auto_id');
          $this->data = array(
               'disp_name'=>$session->get('disp_name'),
               'pic_url'=>$session->get('pic_url'),
               'gender'=>$session->get('gender'),
               'user_role'=>$session->get('user_role'),
               'lat'=>$session->get('lat'),
               'long'=>$session->get('long'),
               'newregister'=>$session->get('newregister')
          );
     }

     // return the user id
     public function id()
     {
      return $this->id;
     }

     // the __get magic method is called when trying to retrieve a value of a
     // property that has not been defined.
     public function __get($name)
     {
      if(array_key_exists($name, $this->data))
      {
       return $this->data[$name];
      }
      return null;
     }


     // the __set magic method is called when trying to store a value in a property
     // that has not been defined.
     public function __set($name, $value)
     {
      global $session;
      // check if the key exists in the 'data' array.
      // if so, set the value in the array as well as the session
      if(array_key_exists($name, $this->data))
      {
       $this->data[$name] = $value;
       $session->set($name, $value);
      }
     }
}

This way you can still get and set values the same as you were, but will also store the set the value in your session class.

To test this:

$user = new User;
if($user->id())
{
     echo $user->disp_name;
     $user->disp_name = 'new name';
     echo $session->get('disp_name');
}
CommissarXiii
A: 

I would not suggest you that because:

  1. It is not a good practice to select an architecture "in case of future need" ('the reason I made it was so I could easily change'). Check http://www.startuplessonslearned.com (Eric Ries) or http://highscalability.com articles
  2. Your code is hard/impossible to test (See Misko Hevery's blog (A google evangelist) http://misko.hevery.com for further information).
  3. You are using "global" (never a good idea if you want to keep track of the dependencies).
  4. It is better to seperate "the business logic" (a User class) and the wiring/building (a factory class for example). (See http://en.wikipedia.org/wiki/Single_responsibility_principle and "separation of concerns")

For really good code examples (and to understand which OO laws should not be broken), I can advice you Misko's blog (Also do not miss his technical talks at google that you can find on youtube). I am sure you will love them.

Hope this helps.

Toto