Page 1 of 2
How do i keep singleton class object in a session?
Posted: Tue Aug 07, 2007 3:14 am
by niro121
feyd | Please use Code: Select all
and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read: [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
Hi
I'm Niro, a student from sri lanka. I am stuck with some php problem. I hope you can help me with this. I'm using singleton design pattern. But im stuck with a problem.
the application is something like this.
using singleton when he enters my account page he is instanciated a logger class instance. object is created. Now its working fine.
Code: Select all
$log = Logger::getInstance();
$log->Log(5);
echo "{$log->user->getUserTable()}<br>";
$_SESSION['logger'] = serialize($log);
then for me i need this class object to take in the session. so what i did was serialize the object and unserialize from my next page to the same object name to retrieve it. then i call getInstance method.
Code: Select all
$blob = unserialize($_SESSION['logger']);
$blob = Logger::getInstance();
echo "{$blob->user->getUserTable()}<br>";
But friend it build a new Logger instance who has an attribute called guest not the member (where i have given from the earlier page) . Means it still don't recognize the same object as its getInstance(). Pls help me to find a solution.
How does the singleton design theory really appy when you use sessions. how do we carry the object instanciated from one page and in da next page recognize as the same object. Pls reply me as sson as possible. Thank you very much.
feyd | Please use Code: Select all
and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read: [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
Posted: Tue Aug 07, 2007 4:51 am
by stereofrog
Hi Niro, welcome to the forums.
To answer your question, we need to see how Logger::getInstance is implemented. I can only guess, the unserialization code should be moved to getInstance().
Some programmers (including myself) prefer not to use singletons (because they are not pure-OO) and object persistence (because it's not in the spirit of PHP).
Posted: Tue Aug 07, 2007 5:06 am
by niro121
feyd | Please use Code: Select all
and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read: [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
Hi thanks pal, But is my way is it ok.. Hmmm in my way i wont have to create the instance again and again so that once the member is created the object will have all the datata so its very easy wont have to go for DB query. Hmmmmm why is this instance is not taken?
Hmmmmm am i doing something wrong?
/////////////////////////////////////////////////////////////// This is the Logger /////////////////////////////////////////////////////
Code: Select all
<?php
class Logger {
var $name;
static private $instance = NULL;
//This carries the user instance
var $user;
static function getInstance()
{
if (self::$instance == NULL) {
self::$instance = new Logger();
}
return self::$instance;
}
private function __construct()
{
$this->user = new GuestUser("GUEST");
}
private function __clone()
{
echo " You cannot CLONE this SINGLETON object ";
}
function Log($id)
{
$conn = mysql_connect("localhost","root","arch");
mysql_select_db("success" , $conn) or die( "USER LOG ERROR:".mysql_error());
$result = mysql_query("SELECT * FROM user WHERE id = $id ") or die("USER LOG ERROR:".mysql_error());
$userdata = mysql_fetch_array($result,MYSQL_ASSOC);
if(strtoupper($userdata['username']) == "ADMIN"){
$this->user = new AdminUser($id,"ADMIN");
}
else{
$this->user = new CustomerUser($id,"MEMBER");
}
}
}
?>
/////////////////////////////////////////////////////////////////// This is My first Page ///////////////////////////////////////////////
Code: Select all
<?php
session_start();
include_once('User.php');
include_once('Logger.php');
include_once('AdminUser.php');
include_once('GuestUser.php');
include_once('CustomerUser.php');
include_once('Database.php');
include_once('Property.php');
$log = Logger::getInstance();
// This Log in the user who is having id = 5
$log->Log(5);
// This shows the user data
echo "{$log->user->getUserTable()}<br>";
$_SESSION['logger'] = serialize($log);
?>
///////////////////////////////////////////////////////////////////// This is my second page who will recive the object ///////////
Code: Select all
<?php
session_start();
include_once('User.php');
include_once('Logger.php');
include_once('AdminUser.php');
include_once('GuestUser.php');
include_once('CustomerUser.php');
include_once('Database.php');
include_once('Property.php');
$log = unserialize($_SESSION['logger']);
$log = Logger::getInstance();
// This is to show the user data - I expect the member details but gets a guest details
echo "{$log->user->getUserTable()}<br>";
?>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Problem is log is not seen by the LOgger class as its same object. Is this cos serializion?
feyd | Please use Code: Select all
and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read: [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
Posted: Tue Aug 07, 2007 5:19 am
by superdezign
I'm a fan of singletons, as they make accessing needing objects simple without needing to send the references from one constructor to the next.
You either want to utilize the __sleep() and __wakeup() functions, create a "setInstance()" method that you could call after you start the session, put the session into account in your getInstance() method, or just discard the one in the session if it's no different than creating another one.
Posted: Tue Aug 07, 2007 5:20 am
by stereofrog
Before we delve into why this doesn't work, can you explain why you need this (i.e. to serialize and store logger in the session)?
Posted: Tue Aug 07, 2007 5:44 am
by niro121
yes, hmmm this is my plan.
I need to create a logger object. when somebody loggs, in the log() function is taking the id and creates a cutomerUser or Admin. But if the log function is not called or no prevailing object as logger is there the LOGGER class from getInstance() function is creating a guest user defalt.
Now my Logger object is ok.
It contains a $user (that is actually an object and) it contains user data. All the userdata, like address and all. Done from User class and DB queries.
Now is going to next page. Carry the Logger Object. To next page.
When i go to next page i don't want to create the Logger again. I call getInstance(). If the session has logger object that means a prevailing Logger is there . It can be CutomerUser , Guest, Or Admin. But if the session is not having a $_SESSION['logger']; getInstance() will create a New Guest user.
So thats my plan.
Hmmmm but only thing is i dont see how i take the Logger object taken from one page to another. So for that i have done it as a serialization fassion. So in the last page object is created (unzerialized). but i do call the getInstance() thats cos singleton. So in singleton if the object is there no new thing will be created. Isnt it. But... its not working.. any idea?
Posted: Tue Aug 07, 2007 6:08 am
by stereofrog
Ok, I see. First off, I find your naming confusing. What your class does is called Authorization (
http://en.wikipedia.org/wiki/Authorization) which involves "Log-In" function and has nothing to do with "Logging" (
http://en.wikipedia.org/wiki/Data_logging).
It's not clear to me why you need a separate Authorization object here, but there definitely no need to persist it in session.. The only thing you need to save is an ID of the logged-in user. On page start, check the id and restore the authorization state.
Example:
Code: Select all
# try to login using form data
if(...post from the login form...)
{
# if usename/password ok
if(Auth::login($_POST['username'], $_POST['password']))
# save user id in the session
$_SESSION['auth_user_id'] = Auth::userId();
}
else
# try to restore from session
if(isset($_SESSION['auth_user_id']))
Auth::restore($_SESSION['auth_user_id']);
if(Auth::valid())
echo "secret data";
else
echo "please login first!";
Posted: Tue Aug 07, 2007 6:27 am
by niro121

thanks stereofrog, yea i'm really new to this design patterns sorry for any mistakes. My intention is keeping the Auth object alive. It contains userdata which is queried from DB. But if i do something like yours i have to created the Auth object again and again in every page. So each and everytime the DB is queried and data is taken. What i thought is in singleton we can have one object alive. So if Auth object is there no new object created. And less DB access. But for that i need Auth object to carry forward from that page to next page... Im trying to test singleton in my site so i will learn its worthiness. I want to know how it is being done in industry.
Hmmm.. i used to create every object like that in every page. Thats loads of coding. I'm not being lazy but i need to know whats our fellows use in industry. Do they carry objects from page to page or re-create them again and again in each page..

Posted: Tue Aug 07, 2007 7:09 am
by stereofrog
The common practice in php is to reconstruct working objects on every page call. The reason is that php doesn't support object persistence. The advantage of "reconstruction" model is much simpler programming, at the price of higher overhead at start time. Of course, this doesn't mean you have to repeat the respective php code on every page, just use include/require wherever needed.
Posted: Tue Aug 07, 2007 7:21 am
by niro121
Posted: Tue Aug 07, 2007 2:11 pm
by AKA Panama Jack
Man, I need to have a Macro for this...
Objects cannot and will not persist between executions of different PHP scripts. You cannot store an object in a session variable and expect to access the object in another PHP script. All objects are immediately DESTROYED when a PHP script finishes executing. You have to build a NEW object every single time you execute a PHP script.
$_SESSION['myobject'] = new myobject();
That will store a POINTER in the session array that points to an object.
When the PHP script that created the object finishes executing the object that pointer pointed too is DESTROYED and removed from memory.
When a new PHP script is executed the $_SESSION['myobject'] variable will contain a pointer to a NON-EXISTENT object. There will be nothing there for you to access as the object the pointer used to point to is gone, forever. You will need to create the object all over again.
There isn't anything such as Object Persistence in PHP.
Posted: Tue Aug 07, 2007 2:34 pm
by TheMoose
Use a database as your state store. You can set $_SESSION values to act as reminders of where to find the data, and what data to get, but use a database to store exactly what data you need. It helps in 2 ways, if the objects you're creating to begin with work off the database, having the data in a single location prevents extra disk usage, but also prevents mismatched data from being stored in separate locations (the PHP script data could be different from DB data).
In this case, you have a "guest" account that is being used. If you create an initial account in your users table that has just basic guest privileges, you can have your Logger object get the user data based off a known ID number (say ID 1 is the guest account). This way the only thing you need to save in your session is $_SESSION['userid']=1, and your Logger knows to get the user id from the session, and base it's actions off the guest account 1 from the database.
Posted: Tue Aug 07, 2007 2:46 pm
by stereofrog
AKA Panama Jack wrote:
$_SESSION['myobject'] = new myobject();
That will store a POINTER in the session array that points to an object.
This will store the serialized representation of the object. Unless the object contains non-serializable elements (i.e. resources), it's quite easy to restore it from the session. Another thing, you don't need this.
Posted: Tue Aug 07, 2007 2:50 pm
by Weirdan
You cannot store an object in a session variable and expect to access the object in another PHP script.
but when an object is placed into the $_SESSION array its internal state automatically serialized upon the end of the request and then automatically restored in the next request cycle, so effectively you can persist the object.
Posted: Tue Aug 07, 2007 3:39 pm
by ev0l
AKA Panama Jack wrote:Man, I need to have a Macro for this...
Objects cannot and will not persist between executions of different PHP scripts. You cannot store an object in a session variable and expect to access the object in another PHP script.
This is totally and entirely incorrect! The only thing that cannot be persisted in a PHP session is a resource.
There is nothing wrong with storing objects in your session. If you have transient data that is associated with the users session and does not need to persist past the end of your users session store it in $_SESSION. That is why it is there.
Object serialization/deserialization is a fast process. Faster, in fact, then storing that data in a database and reconstructing it on each request. If speed does in fact become an issue there are a number of ways to speed up the reconstruction of session objects, like storing session data on a tmpfs. My advice to you, niro121, is don't worry to much about performance until you start to see performance problems. Focus more on a clean and simple design.
You don't need to serialize an object before you place it in your session. PHP will do that for you. It will also unserialize it on the next request. My advice is to simplify. Don't use a pattern if it is not needed. Use the instance of Logger that is stored in your session.
Code: Select all
$log = Logger::getInstance();
$log->Log(5);
echo "{$log->user->getUserTable()}<br>";
$_SESSION['logger'] = $log;
/*
**Next request follows
*/
$blob = $_SESSION['logger'];
echo "{$blob->user->getUserTable()}<br>";
Keep it simple and clear.
Also I advise you to think of objects as nouns. Objects should be things that may or may not do stuff. Object should not be doers. If might be better if your Logger class was an object representation of a Log. You could then read/write/report on that log all using the same class.
Keep up the good work.