TalkPHP
 
 
Account Login
Latest Articles
» The basic usage of PHPTAL, a XML/XHTML template library for PHP
» Vulnerable methods and the areas they are commonly trusted in.
» Simple way to protect a form from bot
» The Basics On: How Session Stealing Works
» How to keep your forms from double posting data
Advertisement
Associates
Associates
techtuts Darkmindz
CSS Tutorials Tutorialsphere.com - Free Online Tutorials
Boston PHP SurfnLearn
Reply
 
LinkBack (3) Thread Tools Search this Thread Display Modes
Old 10-14-2007, 05:28 PM   3 links from elsewhere to this Post. Click to view. #1 (permalink)
The Reckoner
Advanced Programmer Top Contributor 
 
Karl's Avatar
 
Join Date: Sep 2007
Posts: 438
Thanks: 22
Karl is on a distinguished road
Default How to use the Singleton design pattern

The Singleton Pattern is one of the GoF (Gang of Four) Patterns. This particular pattern provides a method for limiting the number of instances of an object to just one. It's an easy pattern to grasp once you get past the strange syntax used.

Consider the following class:

PHP Code:
class Database
{
    public function 
__construct() { ... }
    public function 
connect() { ... }
    public function 
query() { ... }
    ...

This class creates a connection to our database. Any time we need a connection we create an instance of the class, such as:

PHP Code:
$pDatabase = new Database();
$aResult $pDatabase->query('...'); 
Lets say we use the above method many times during a script's lifetime, each time we create an instance we're creating a new Database object (we're also creating a new database connection, but that's irrelevant in this example) and thus using more memory. Sometimes you may intentionally want to have multiple instances of a class but in this case we don't.

The Singleton method is a solution to this common problem. To make the Database class a Singleton we first need to add a new property to the class, we'll call this $m_pInstance:

PHP Code:
class Database
{
    
// Store the single instance of Database
    
private static $m_pInstance;

    ...    

As the comment states, this property will be used to store the single instance of our Database class. You should also note that this property must be static.

Next we need to change the constructor's scope to private. This is one of the strange syntaxes that usually confuse people.

PHP Code:
class Database
{
    
// Store the single instance of Database
    
private static $m_pInstance;

    private function 
__construct() { ... }

By making the constructor private we have prohibited objects of the class from being instantiated from outside the class. So for example the following no longer works outside the class:

PHP Code:
$pDatabase = new Database(); 
We now need to add a method for creating and returning our Singleton. Add the following method to the Database class:

PHP Code:
public static function getInstance()
{
    if (!
self::$m_pInstance)
    {
        
self::$m_pInstance = new Database();
    }

    return 
self::$m_pInstance;

This funny looking function is responsible for handling our object instance. It's relatively easy to understand, basically we check our static property $m_pInstance, if it is not valid we create a new instance of the Database class by calling the constructor. Remember, we made the __construct() method private, so an instance of the object can only be created from within the class' methods. Finally the function returns a reference to our static property. On subsequent calls to getInstance(), $m_pInstance will be valid and thus the reference will be returned - no new instances are created.

So our Database class now looks something like this

PHP Code:
class Database
{
    
// Store the single instance of Database
    
private static $m_pInstance;

    private function 
__construct() { ... }

    public static function 
getInstance()
    {
        if (!
self::$m_pInstance)
        {
            
self::$m_pInstance = new Database();
        }

        return 
self::$m_pInstance;
    }

You can now get an instance of the Database class from anywhere (without using globals or function arguments) in your project. Here's an example and comparison:

This is the usual way we create objects:
PHP Code:
$pDatabase = new Database();
$aResult $pDatabase->query('...'); 
This is the Singleton way:
PHP Code:
$pDatabase Database::getInstance();
$aResult $pDatabase->query('...'); 
To conclude, the Singleton is an easy-to-use design pattern for limiting the number of instances of an object. See the attached files for working examples.
Attached Files
File Type: php default.php (776 Bytes, 791 views)
File Type: php singleton.php (1.1 KB, 955 views)
__________________
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
Karl is offline  
Reply With Quote
Old 10-14-2007, 07:24 PM   #2 (permalink)
The Gregarious
Upcoming Programmer Inquisitive 
 
Join Date: Sep 2007
Posts: 748
Thanks: 85
Tanax is on a distinguished road
Default

Looks nice :D I will study the examples ;)

And thanks for a great tutorial :)
Tanax is offline  
Reply With Quote
Old 10-20-2007, 07:16 PM   #3 (permalink)
The Gregarious
Advanced Programmer Top Contributor Good Samaritan 
 
sketchMedia's Avatar
 
Join Date: Oct 2007
Location: Manchester, UK
Posts: 532
Thanks: 26
sketchMedia is on a distinguished road
Default

to further enforce this pattern you may want to either make the magic method __clone() private or just make the script die when this function is called, this is so that clones of the singleton object cannot be made.
__________________
sketchMedia is offline  
Reply With Quote
Old 11-01-2007, 01:45 AM   #4 (permalink)
La Vida es Sueño
Advanced Programmer Top Contributor 
 
Wildhoney's Avatar
 
Join Date: Sep 2007
Location: Oldham
Posts: 1,654
Thanks: 73
Wildhoney is on a distinguished road
Default

What a great PHP singleton tutorial. By implementing the __clone method you certainly won't be getting past it!
__________________
The man who comes back through the Door in the Wall will never be quite the same as the man who went out.
Send a message via AIM to Wildhoney Send a message via MSN to Wildhoney Send a message via Yahoo to Wildhoney
Wildhoney is offline  
Reply With Quote
Old 11-01-2007, 10:39 AM   #5 (permalink)
daz
The Contributor
Upcoming Programmer 
 
Join Date: Sep 2007
Posts: 31
Thanks: 0
daz is on a distinguished road
Default

Great tutorial, I will definitely use this technique in my coding.
daz is offline  
Reply With Quote
Old 05-08-2008, 09:52 PM   #6 (permalink)
The Visitor
 
Join Date: May 2008
Posts: 1
Thanks: 0
Prpl_Ppl_Etr is on a distinguished road
Default

I'm having some trouble getting my Singleton to hold state.

I have a class that implements the Singleton pattern and has a member called $sessionState which is meant to hold a string value denoting the current state of the Singleton instance.

Now, maybe it's my lack of understanding when it comes to sessions, but every time I retrieve an instance of my Singleton class, the $sessionState member gets reset.

Code fragments follow:

PHP Code:
class Control{
    
    private static 
$sessionState;
    
    private static 
$instance;
    
    
// private constructor
    
private function __construct(){
        
// initalize state value
        
self::$sessionState='Not Initialized';
    }
    
    
// the getInstance() method returns a single instance of the object
    
public static function getInstance(){
        if(empty(
self::$instance)){
            
self::$instance=new Control();
        }
        return 
self::$instance;
    }

    
    
    public function 
Initialize(){
        
$return// either 'true' or 'false'
        
switch(self::$sessionState){
            case 
'Not Initialized':
                
$monitor=SessionMonitor::getInstance();
                
$initialized=$monitor->initialize();
                if(
$initialized=='false'){
                    
$this->setErrorCode('102');
                    
$return='false';
                }else{
                    
self::$sessionState='Running';
                    
$this->setErrorCode('0');
                    
$return='true';
                }
            break;
            case 
'Running':
                
$this->setErrorCode('103');
                
$return='false';
            break;
            case 
'Terminated':
                
$this->setErrorCode('104');
                
$return='false';
            break;
            default:
                
$this->setErrorCode('101');
                
$return='false';
        }
        return 
$return;
    }

As you can see, I want the Initialize method to check the current value of $sessionState and respond accordingly. After a successful intialization of SessionMonitor, the $sessionState should be updated from 'Not Initialized' to 'Running' (which testing proves DOES happen). I'd expect, then, that any subsequent calls to other Control methods which depend on the value of $sessionState would read a value of 'Running'.

Such as...

PHP Code:
public function GetValue($cmi,$dbConn){
        
$return//either a string value or empty string
        
switch(self::$sessionState){
            case 
'Not Initialized':
                
$this->setErrorCode('122');
                
$return='';
            break;
            case 
'Running':
                
// get the type of model element
                
$cmiObject=$this->getCMIObject($cmi);
                
// 
                
$return=$cmiObject->getValue($dbConn);
                if(
$return==false){
                    
$error=$cmiObject->getError();
                    
$this->setErrorCode($error->errorCode);
                    
$return='';
                }else{
                    
$this->setErrorCode('0');
                }
            break;
            case 
'Terminated':
                
$this->setErrorCode('123');
                
$return='';
            break;
            default:
                
$this->setErrorCode('101');
                
$return='';
        }
        return 
$return;
    } 
If I call this method (after a successful call to Initialize), the case block for 'Running' doesn't execute, as the value for $sessionState seems to get reset to 'Not Initialized'.

What am I missing? Are Singleton instances cleared/collected with subsequent http requests to the same php file?
Prpl_Ppl_Etr is offline  
Reply With Quote
Reply


LinkBacks (?)
LinkBack to this Thread: http://www.talkphp.com/advanced-php-programming/1304-how-use-singleton-design-pattern.html
Posted By For Type Date
Building an Apache-like Access Control List (ACL) - TalkPHP This thread Refback 01-03-2008 06:10 AM
PHP Advanced PHP: How to use the Singleton Design Pattern Tutorial This thread Refback 12-22-2007 11:11 AM
PHP OOP Advanced PHP: How to use the Singleton Design Pattern Tutorial This thread Refback 12-21-2007 09:55 PM

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


All times are GMT. The time now is 06:33 AM.

 
     

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0