Design Patterns (and anti-patterns) are techniques of programming. There are a lot of design patterns. It is upto the programmer to pick and choose which patterns to use based on their needs. Singleton is also a design pattern. A singleton is a type of class which can have only 1 object of its kind through the lifecycle of an application. It is very suitable for database, caching, etc. I will use a database class as an example as it is probably the most-widely used class in web development.
Why use a singleton you ask? A popular practice among PHP4’s developers is to make a database object global then use that variable anything a query needs to be run. It works in small applications and even in not-so-big applications. In enterprise applications where you use hundreds (if not thousands) of variables, there is a very good chance that you database object will get mutated or overridden. You also don’t want to have multiple instance of a database class (unless you are running a multi-threaded application).
A database class should be able to connect to a database, run queries, return results and close the connection to the database when it’s done. Keeping that in mind, let’s start writing our database class.
/**
* Database wrapper
*/
class Database {
private $_host;
private $_user;
private $_pass;
private $_name;
private $_conn;
private $_err;
/**
* Setting the constructor as private will make sure
* that the class cannot be instantiated using the
* "new" keyword. You can to instantiate it like this :
* $db = Database::getInstance();
* getInstance() is implemented right after the constructor
*/
private function __construct($host, $user, $pass, $name)
{
$this->_host = $host;
$this->_user = $user;
$this->_pass = $pass;
$this->_name = $name;
}
/**
* This function is what makes this whole class a singleton.
* It will make sure only one instance of this class is available
*/
function getInstance($host='', $user='', $pass='', $name='')
{
static $obj;
if (null == $obj) {
$obj = new Database($host, $user, $pass, $name);
$obj->connect();
}
return obj;
}
/**
* Connects to the database
*/
function connect()
{
$this->_err = null;
if (!mysql_connect($this->_host, $this->_user, $this->_pass)) {
$this->_err = mysql_error();
return false;
}
if (!mysql_select_db($this->_name)) {
$this->_err = mysql_error();
return false;
}
return true;
}
function error()
{
return $this->_err;
}
function user($val=null)
{
if (null == $val) return $this->_user;
$this->_user = $val;
}
function host($val=null)
{
if (null == $val) return $this->_host;
$this->_host = $val;
}
function pass($val=null)
{
if (null == $val) return $this->_pass;
$this->_pass = $val;
}
function name($val=null)
{
if (null == $val) return $this->_name;
$this->_name = $val;
}
}
So, we wrote a class called database and made its constructor private so you can’t instantiate it using the “new” keyword. We also wrote a method/function for this class called getInstance() which will return a database object. getInstance() has a local static variable called $obj. It checks if this variable is null. If it’s null then that means there is no object of the type “Database”. So, it creates an object and assigns it to $obj. It also returns the object to the code that called it. Setting permissions of private, protected and public could not have been done in PHP 4, which frustrated a lot of OOP enthusiasts. PHP 5, however, has the capability of doing it and thus fulfilling one of OOP’s main goals – encapsulation.
The first timeĀ an object of the class Database is instantiated, it will have to pass all the variables required to make a database connection. Its subsequent calls need not do that.
// First call
$db = Database::getInstance('localhost', 'root', '', 'myDB');
function hello()
{
// Second call
$database = Database::getInstance();
}
Both $db and $database point to the same object. Any changes made to $database will be reflected in $db also. This eliminates the use of global variables for quite a few things (especially our database class).