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).
Leave a Reply