How do i keep singleton class object in a session?

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

niro121
Forum Newbie
Posts: 9
Joined: Tue Aug 07, 2007 2:34 am

How do i keep singleton class object in a session?

Post by niro121 »

feyd | Please use

Code: Select all

,

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

,

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]
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post 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).
niro121
Forum Newbie
Posts: 9
Joined: Tue Aug 07, 2007 2:34 am

Post by niro121 »

feyd | Please use

Code: Select all

,

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

,

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]
User avatar
superdezign
DevNet Master
Posts: 4135
Joined: Sat Jan 20, 2007 11:06 pm

Post 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.
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post 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)?
niro121
Forum Newbie
Posts: 9
Joined: Tue Aug 07, 2007 2:34 am

Post 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?
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post 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!";
niro121
Forum Newbie
Posts: 9
Joined: Tue Aug 07, 2007 2:34 am

Post by niro121 »

:D 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.. :?:
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post 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.
niro121
Forum Newbie
Posts: 9
Joined: Tue Aug 07, 2007 2:34 am

Post by niro121 »

I appreciate your comment. Yea thats great to here what you guys use actually. I too need to know more about this object persistence. At least if we can mimic something like that. Something like i try. Only concern is with re-constructing objects having to pay the initial overload, is it worthy? if we do create complex objects hows about the speed. If you guys use it for big sites meas its not that slow right? So does this mean the method of taking objects page to page (in someway like serialization )is used? If so for how extent?. Wow I learned a lot today. He he thanks.. want to visit this forum everyday.. :D :D :D
User avatar
AKA Panama Jack
Forum Regular
Posts: 878
Joined: Mon Nov 14, 2005 4:21 pm

Post 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.
User avatar
TheMoose
Forum Contributor
Posts: 351
Joined: Tue May 23, 2006 10:42 am

Post by TheMoose »

niro121 wrote:I appreciate your comment. Yea thats great to here what you guys use actually. I too need to know more about this object persistence. At least if we can mimic something like that. Something like i try. Only concern is with re-constructing objects having to pay the initial overload, is it worthy? if we do create complex objects hows about the speed. If you guys use it for big sites meas its not that slow right? So does this mean the method of taking objects page to page (in someway like serialization )is used? If so for how extent?. Wow I learned a lot today. He he thanks.. want to visit this forum everyday.. :D :D :D
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.
User avatar
stereofrog
Forum Contributor
Posts: 386
Joined: Mon Dec 04, 2006 6:10 am

Post 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.
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Post 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.
ev0l
Forum Commoner
Posts: 56
Joined: Thu Jun 21, 2007 1:50 pm

Post 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.
Post Reply