PHP4 Tricks: The Singleton Pattern – Part II
In the previous article we took a look at one possible implementation of the Singleton design pattern in PHP4. In this second installation, we take a look at some possible applications for it.
In [part one][part-1], we went through the basics of the Singleton design pattern. We ended up with two classes:
An
Objectclass that we can use as a base for our classes. This class takes care of object construction through a__construct()method as found in PHP5.A
SingletonInterfaceclass that we can use as a base for Singleton classes. This guarantees that we have a consistent interface for all Singleton objects in our application.
Simulating Namespaces
One of the important things that PHP4 (and PHP5!) lacks is the concept of namespaces. If you have ever programmed in C++, C#, or Java you will be familiar with the concept of namespaces. For those who are not familiar with it, a namespace can be thought of as a named boundary within your program that can contain variables and functions. In other programming languages it is also possible for a namespace to hold classes and even other namespaces. One of the main reasoning behind the concept of namespaces is to prevent naming clashes between software libraries.
Using a namespace, you can create global variables under one namespace without having to worry about another global variable with the same name under another namespace. The two global variables are treated as two different global variables even though they have the same name.
Now that we have a workable implementation of a SingletonInterface, it’s time to put it to use. One of the most useful applications of a Singleton in PHP4 (and PHP5) is to create a namespace to place our “global” variables under. For example:
class MyGlobals extends SingletonInterface {
var $_properties = array();
function &getPropByRef($propName) {
static $_null = null;
$_this =& MyGlobals::getInstance();
if (isset($_this->_properties[$propName])) {
return $_this->_properties[$propName];
}
else {
return $_null;
}
}
function getPropByVal($propName) {
$_this =& MyGlobals::getInstance();
if (isset($_this->_properties[$propName])) {
return $_this->_properties[$propName];
}
else {
return null;
}
}
function setPropByRef($propName, &$value) {
$_this =& MyGlobals::getInstance();
$_this->_properties[$propName] =& $value;
}
function setProfByVal($propName, $value) {
$_this =& MyGlobals::getInstance();
$_this->_properties[$propName] = $value;
}
function __construct() {
// Perform object initialization here.
parent::__construct();
}
function &getInstance() {
return parent::__getInstanceImp(’MyGlobals’);
}
}
We define two types of setters and getters here. One type deals with references and the other type deals with values. This is important because under PHP4, object copy semantics are slightly different from PHP5. Assigning an object to another variable name in PHP4 will result in a deep copy operation. Depending on what the program is trying to do, this can lead to some unexpected results and subtle errors that are very hard to find.
Consequently, the notion of using a Singleton to simulate a namespace extends to the idea of “packages”. A package is a collection of related variables and functions (in other languages, they can also contain other packages as well as classes) that can be accessed using a single namespace.
The functions and variables in a package can be defined as static methods and properties of a class in other languages. In PHP4, while we do have a way of implementing static methods, we have no way of implementing static properties.
This next example takes the notion of simulated namespaces further by defining “static” methods. We call them “static” methods because they make use of “static” properties.
class MyPackage extends SingletonInterface {
var $staticProperty1;
var $staticProperty2;
function staticFunction1() {
$_this =& MyPackage::getInstance();
$_this->staticProperty1 = ‘Changed some value’;
}
function staticFunction2() {
$_this =& MyPackage::getInstance();
$_this->staticProperty2 = ‘Changed another value’;
}
function __construct() {
// Perform object initialization here.
parent::__construct();
$this->staticProperty1 = ’some value’;
$this->staticProperty2 = ‘another value’;
}
function &getInstance() {
return parent::__getInstanceImp(’MyPackage’);
}
}
MyPackage::staticFunction1();
MyPackage::staticFunction2();
$pkg =& MyPackage::getInstance();
echo “{$pkg->staticProperty1}\n”;
echo “{$pkg->staticProperty2}\n”;
Everything Else Follows…
From these two basic notions, we can come up with many other ways of using the Singleton pattern in our programs. Using Singletons in place of global variables in PHP4 helps to avoid many of the security mishaps that result in the use of global variables. Although there is no silver bullet to creating a completely secure program (much less a secure program in PHP4!), completely eliminating the use of globals is a step in the right direction.
Using Singletons to implement “packages” allows for greater code re-use in PHP4. Although you can always create “packages” by placing all your related functions and globals in one file, you have to contend with naming conflicts as your program grows or as you rely on more and more third-party libraries.
As I have said above, you can extend on the basic notion of the namespace and packages and use the Singleton design pattern to implement the following:
Centralized configuration object – all the configuration variables and properties that should be accessible during the lifetime of your program can be in one place. This makes it easier to debug your application and it also simplifies the process of performing audits.
Wrapping superglobals with an object – although not really necessary, wrapping superglobals such as
$_SERVER,$_REQUEST, and$_COOKIESinto a singleton can be useful when building a library. You can abstract away the details of where these values are coming from and at the same time, you can perform filtering on incoming superglobal values.Maintain several database connections – for small to medium-sized applications, a single database connection to a single server will normally suffice. For larger, enterprise-level applications however, you may need to connect to more than one database server.
Create an “object factory” – a more advanced use case would be to use a Singleton as an object factory. An object factory takes care of instantiating and initializing objects from many different classes and hands them off to the client code. Consequently, objects created by the factory are “registered” into an internal object registry allowing the client code to re-use an instance of an object. The SingletonInterface class is one example of such a factory.
Code re-use, security, and overall ease of maintenance. These are just some of the benefits of using a Singleton in your programs. If you find other uses for this code, or if you have any corrections to make, please post your comments. Please note that I reserve the right to select or reject comments for publishing.
[part-1]: /posts/2006/php4-tricks-the-singleton-pattern-part-i/ “PHP4 Tricks: The Singleton Pattern – Part I”

March 6th, 2007 at 5:39 am
I’m passing my instance of the singleton arguments in the constructor, but I’m not getting the values, how do i access them? What am I doing wrong, thanks!
March 6th, 2007 at 7:30 am
I am not sure I understand what you are trying to do really, but as far as I can tell from your example code, you need to implement
userAccess::getInstance()anduserAccess::__construct()as follows:I’m just guessing here and in the implementation above, the three parameters are optional and are only used if they are provided. But if you require parameters to your
getInstancemethod, you would be hard pressed to provide them every time you want an instance of your singleton. Of course, with the above implementation you can initialize the singleton somewhere in your program and the callgetInstanceas usual.April 18th, 2007 at 3:21 am
Thanks for this informative article! I’ve found it very useful in writing a config class for a PHP4 app. (PEAR::Config was not right for my needs, and the new Zend Framework requires PHP 5.1.4)