The singleton pattern is probably the most infamous pattern to exist and is considered an anti-pattern because it creates global variables that can be accessed and changed from anywhere in the code.
Yet, The use of the singleton pattern is justified in those cases where we want to restrict the number of instances that we create from a class in order to save the system resources. Such cases include database connections as well as external APIs that devour our system resources.
We use the singleton pattern in order to restrict the number of instances that can be created from a resource-consuming class to only one.
Resource consuming classes are classes that might slow down our website or cost money. For example
- Some external service providers (APIs) charge money per use.
- Some classes that detect mobile devices might slow down our website.
- Establishing a connection with a database is time-consuming and slows down our app.
Let's start by understanding the structural characteristics of a class that obeys the singleton pattern:
- A private constructor is used to prevent the direct creation of objects from the class.
- The expensive process is performed within the private constructor.
- The only way to create an instance from the class is by using a static method that creates the object only if it wasn't already created.
// General singleton class.
class Singleton {
// Hold the class instance.
private static $instance = null;
// The constructor is private
// to prevent initiation with outer code.
private function __construct()
{
// The expensive process (e.g.,db connection) goes here.
}
// The object is created from within the class itself
// only if the class has no instance.
public static function getInstance()
{
if (self::$instance == null)
{
self::$instance = new Singleton();
}
return self::$instance;
}
}
Since we restrict the number of objects that can be created from a class to only one, we end up with all the variables pointing to the same, single object.
// All the variables point to the same object.
$object1 = Singleton::getInstance();
$object2 = Singleton::getInstance();
$object3 = Singleton::getInstance();
Practical example:: database class
Let's demonstrate the singleton pattern with a class that establishes a database connection, and restricts the number of instances to only one.
// Singleton to connect db.
class ConnectDb {
// Hold the class instance.
private static $instance = null;
private $conn;
private $host = 'localhost';
private $user = 'db user-name';
private $pass = 'db password';
private $name = 'db name';
// The db connection is established in the private constructor.
private function __construct()
{
$this->conn = new PDO("mysql:host={$this->host};
dbname={$this->name}", $this->user,$this->pass,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
}
public static function getInstance()
{
if(!self::$instance)
{
self::$instance = new ConnectDb();
}
return self::$instance;
}
public function getConnection()
{
return $this->conn;
}
}
Since we use a class that checks if a connection already exists before it establishes a new one, it really doesn't matter how many times we create a new object out of the class, we still get the same connection. To prove the point, let's create three instances out of the class and var dump them
$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);
$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);
$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);
The singleton pattern is probably the most infamous pattern to exist and is considered an anti-pattern because it creates global variables that can be accessed and changed from anywhere in the code.
Yet, The use of the singleton pattern is justified in those cases where we want to restrict the number of instances that we create from a class in order to save the system resources. Such cases include database connections as well as external APIs that devour our system resources.
Mahmoud Abd Elhalim
I am a professional web developer with years of experience in the web applications and software industry, Follow me to got more..
Comments