As you probably know, in software engineering there is a set of design patterns that are universally tested, approved and accepted as advanced recipes for programming. One of these patterns is the Singleton design pattern, which is based on the mathematical concept of a singleton (a set with a single element). Part of the well-known Gang of Four (GoF) design patterns, it calls for restricting the instantiation of a class to one object. (Those who are familiar with design patterns may be interested to know that the Singleton pattern in itself is an implementation of the Responsibility pattern.)
Sometimes the Singleton pattern can help complete important programming tasks, but only you can decide where and when it fits your needs. As a pointer, the Singleton pattern fits well when you manage a shared resource -- a printer, a file manager, a database connection, loggers, and so on -- because your application should have only a single instance in order to avoid conflicting requests for the same resource and to minimize performance issues.
Before deciding to use the Singleton pattern, you should first answer "yes" to three main questions:
  1. Do you need concurrent access to a shared resource by the entire application?
  2. Will there be requests from multiple, disparate parts of the system?
  3. Do you need only one global object?
Figure 1 breaks the Singleton pattern down into programming concepts. It is a UML class diagram of a Singleton class.

Figure 1. Singleton Pattern UML Class Diagram
In this article, I explain how to implement the Singleton pattern in different ways for different purposes in PHP 5.

Implementing a Singleton Class Template

In this section, you will create a PHP Singleton class template. It will be a common PHP class, except that it will have only one instance and provide a global point to access it. Keeping this in mind, you can develop a Singleton PHP class as follows:
  1. Declare a private static member variable for storing the instance of that class. This is the object instance:
    private static $_instance = null;
  2. Lock down the class constructor by declaring it as private. This will make the class externally "uninstantiable":
    private function __construct() { }
  3. Prevent external instantiation of copies of Singleton class. Locking down clone and wakeup methods will prevent duplicate objects (clones).
    public function __clone() {
    trigger_error( "Cannot clone instance of Singleton pattern ...", E_USER_ERROR );
    }
    public function __wakeup() {
    trigger_error('Cannot deserialize instance of Singleton pattern ...', E_USER_ERROR );
    }
  4. Declare a public static method that creates a single instance of that class. It checks if an instance already exists. If it does, it returns the same instance each time it is called. Otherwise, it creates an instance, stores it in the static member variable and returns it.
    public static function getInstance()
    {
    if( !is_object(self::$_instance) )
    //or if( is_null(self::$_instance) ) or if( self::$_instance == null )
    self::$_instance = new self;
    //or, in PHP 5.3.0
    //if (empty(static::$_instance)) {
    // $class = get_called_class();
    // static::$_instance = new $class;
    //}
    return self::$_instance;
    }
Now, the Singleton class template is ready, and it looks like this:
class SingletonClass
{
//A static member variable representing the class instance
private static $_instance = null;
//Locked down the constructor, therefore the class cannot be externally instantiated
private function __construct() { }
//Prevent any object or instance of that class to be cloned
public function __clone() {
trigger_error( "Cannot clone instance of Singleton pattern ...", E_USER_ERROR );
}
//Prevent any object or instance to be deserialized
public function __wakeup() {
trigger_error('Cannot deserialize instance of Singleton pattern ...', E_USER_ERROR );
}
//Have a single globally accessible static method
public static function getInstance()
{
if( !is_object(self::$_instance) )
//or if( is_null(self::$_instance) ) or if( self::$_instance == null )
self::$_instance = new self;
//or, in PHP 5.3.0
//if (empty(static::$_instance)) {
// $class = get_called_class();
// static::$_instance = new $class;
//}
return self::$_instance;
}
}
For testing your Singleton class, you should add a trivial method to it, like this one:
//The singleton pattern ends here - from this point forward we have the methods of the class
//A simple method to echo something
public function test()
{
echo " 

I'm a method of a singleton class

"; }
Now, you can develop a simple test for the Singleton class. Your test should be focused on trying to create multiple instances of the Singleton class.
- This page tests the SingletonClass class -
 include_once('SingletonClass.php');
$instance_1 = SingletonClass::getInstance();
$instance_2 = SingletonClass::getInstance();
echo("First test:");
$instance_1->test();
echo("Second test:");
$instance_2->test();
//try to clone an instance
echo("Try to clone the singleton instance (if you see blank below, then you better check the logs):");
$cloned = clone $instance_1;
$cloned->test();
?>
The result of this test should output Figure 2.


Click here for larger image

Figure 2. The Output for Test Singleton Class
Note: The error messages returned by the clone and wakeup methods are available in the log folder of your Web container. (If you tested this under Apache HTTP Server, these errors are written in the error.txt file under the /logs folder.)

Develop a Singleton class in Front of Other Classes

A Singleton class can act as a point access for a set of common classes to provide a single instance for each class. Normally, each class can have more than one instance if it is instantiated directly, but it has only one instance if it is instantiated indirectly through the Singleton class. To accomplish this task, the Singleton class will store an array of instances, and each time a new instance is requested, it checks the array for it first. If the requested instance is not found in the array, then a new instance is created and stored in the array for further requests. This class is listed below:
class SingletonForClasses
{
//A static member array representing the classes instances
private static $_instances = array();
//Locked down the constructor, therefore the class cannot be externally instantiated
private function __construct() { }
//Prevent any object or instance of that class to be cloned
public function __clone() {
trigger_error( "Cannot clone instance of Singleton pattern ...", E_USER_ERROR );
}
//Prevent any object or instance to be deserialized
public function __wakeup() {
trigger_error('Cannot deserialize instance of Singleton pattern ...', E_USER_ERROR );
}
//Have a single globally accessible static method
public static function getInstance($_class = null) {
if(is_null( $_class )) {
trigger_error( "Cannot instantiate class, missing class name ...", E_USER_ERROR );
}
if(!array_key_exists( $_class, self::$_instances)) {
echo(" 
Class ".$_class." was instantiated and the
instance was added in the singleton's array ...");
self::$_instances[$_class] = new $_class;
} else {
echo(" 
The instance of ".$_class." was extracted from the
singleton's array ...");
}
return self::$_instances[$_class];
}
}
Now, for testing scopes you can develop two basic PHP classes, like A_class and B_class below:
class A_class
{
public function __construct() { }
public function A_test()
{
echo " 

I'm the A class!

"; } } class B_class { public function __construct() { } public function B_test() { echo "

I'm the B class!

"; } }
Now, you will get a single instance each for A_class and B_class through the above Singleton class, like this (the below code is just a simple test to see if the Singleton class does its job):
- This page tests the SingletonForClasses class -
 include_once('SingletonForClasses.php');
echo("@@@ First call of A_class @@@ - ");
$A_instance_1 = SingletonForClasses::getInstance("A_class");
$A_instance_1->A_test();
echo("@@@ Second call of A_class @@@ - ");
$A_instance_2 = SingletonForClasses::getInstance("A_class");
$A_instance_2->A_test();
echo("@@@ First call of B_class @@@ - ");
$B_instance_1 = SingletonForClasses::getInstance("B_class");
$B_instance_1->B_test();
echo("@@@ Third call of A_class @@@ - ");
$A_instance_3 = SingletonForClasses::getInstance("A_class");
$A_instance_3->A_test();
echo("@@@ Second call of B_class @@@ - ");
$B_instance_2 = SingletonForClasses::getInstance("B_class");
$B_instance_2->B_test();
?>
Running this test will reveal the output from Figure 3.


Click here for larger image

Figure 3. Output for Test Over SingletonForClasses Class

Develop a Singleton Class for Database Connection

A classic task done with Singleton classes is providing resources access through a single instance. For example, a database connection is exactly the type of task that can be done through a Singleton class: you should have one instance communicate with a database because it helps you maintain only one connection instance instead of multiple ones, which might otherwise be resource intensive.
Based on the Singleton template described in the first section of this article, you can write a Singleton class for obtaining database connections, like this:
class DatabaseSingletonClass
{
//set this constants to connect to your database
//the default settings are just for testing tasks
const MYSQL_HOST = "localhost";
const MYSQL_USER = "";
const MYSQL_PASS = "";
const MYSQL_DB = "test";
//A static member variable representing the class instance
private static $_instance = null;
//Locked down the constructor, therefore the class cannot be instantiated
private function __construct() { }
//Prevent any object or instance of that class to be cloned
public function __clone() {
trigger_error( "Cannot clone instance of Singleton pattern ...", E_USER_ERROR );
}
//Prevent any object or instance to be deserialized
public function __wakeup() {
trigger_error('Cannot deserialize instance of Singleton pattern ...', E_USER_ERROR );
}
//Have a single globally accessible static method
public static function getInstance()
{
if( !is_object(self::$_instance) ) {
//or if( is_null(self::$_instance) ) or if( self::$_instance == null )
self::$_instance = new MySQLi(self::MYSQL_HOST, self::MYSQL_USER,
self::MYSQL_PASS, self::MYSQL_DB);
if(self::$_instance->connect_error)
{
throw new Exception('MySQL connection failed: '
. self::$_instance->connect_error);
}
}
return self::$_instance;
}
}
Next, you can develop a simple test for this Singleton, like this:
- This page tests the DatabaseSingletonClass class -
 include_once('DatabaseSingletonClass.php');
$result = DatabaseSingletonClass::getInstance()->query("SELECT * FROM test");
if($result) {
echo("
"); 
while ($row = mysqli_fetch_row($result)) {
echo("
 "); 
for($i = 0; $i < count($row); $i++) {
echo "
 ".$row[$i]." "; 
}
echo("
"); 
}
echo("
");
$result->close();
} else { echo("An error occurred while processing!"); }
?>
The output of this test depends on the database you use. Therefore, no sample output is provided here.

What Is the Risk of Using the Singleton Pattern?

Well, as the saying goes, "too much of anything is never good!" This rule is applicable to the Singleton pattern also, because too much of it will definitely generate some performance issues. So, be careful not to abuse it. Another concern is unit testing, because you will test single objects.
Because these are known risks, you can easily fix them in your applications, but there is one more risk that depends only on programmers and is directly related to their programming expertise and experience. Usually, when inexperienced developers use patterns (not necessarily this one), it leads to performance issues instead of a powerful and robust applications. Therefore, be careful how you integrate design patterns in your applications. Sometimes, assistance from a software architect may be necessary to achieve your desired results.

Conclusion

In this article you saw how to implement the Singleton pattern using PHP 5 capabilities. In future articles, I plan to show the other three patterns from this Gang of Four.

About the Author

Octavia Andreea Anghel is a senior PHP developer currently working as a primary trainer for programming teams that participate at national and international software-development contests. She consults on developing educational projects at a national level. She is a coauthor of the book "XML Technologies: XML in Java" (Albastra, ISBN 978-973-650-210-1), for which she wrote the XML portions. In addition to PHP and XML, she's interested in software architecture, web services, UML, and high-performance unit tests. to e-mail her.