#native_company# #native_desc#
#native_cta#

Implementing the Singleton Pattern in PHP 5 Page 2

By Octavia Andreea Anghel
on November 23, 2010

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