PHP Singleton Pattern – OOP

Commonly when we think of OOP, things like extendsinheritance, visibility and polymorphism are terms that almost always come to mind (or at least should…). We, as developers, are constantly looking for the best approach: what makes my class a reusable object? How can I apply more abstraction? Does my hierarchy make sense? Is this object scalable? etc.

Introduction

Typically, these are very short-minded and simple things developers of all levels think of when their only language for development has been PHP. While “short-minded” may seem a bit harsh, one must realize that there is much more to Object Oriented Programming than what we’ve grown up learning through PHP.  PHP,  while better at OOP as of the 5.x series, still does not have all the available OOP options needed to allow us to code  in a true OOP environment.    I truly believe that this is one reason why developers, like myself, never hear about “patterns” or realize just how important they are are until we feel we’ve mastered all there is to know about development with PHP.

Why?  Well, let’s face it –  As we get better, we become a little more cocky about our approaches and disregard other solutions as unnecessary overhead or a waste of time.

With that being said, the first section of this article will be on misconceptions.   It’s a really short section that covers some common misconceptions developers have of PHP.  If you feel this section isn’t for you, skip on down to the section “What is a Singleton Pattern?”.

Misconceptions

After you work with a language for over a decade, one tends to believe that they’ve covered and exhausted every topic until it’s been beaten to death.  This is unfortunate yet very common.   After working with any language this long its rightfully a belief we obtain not out of ego, but sheer experience.   It’s also extremely true for those of us who, again, have only really developed with a single language (such as PHP) as our main language.

With that in mind, some fundamental misconceptions must be brought to light that we have of PHP with OOP in mind.

  • Misconception #1 – PHP is a true OOP language

This is an unfortunate misconception PHP developers have everywhere.  While PHP has supported OOP since PHP 3.x and gotten a lot better with the 5.x version (5.3x has given us almost 100%), it is still not a 100% or true OOP language.  Simply put, it’s more of a language that supports OOP with a definitive implementation.  One should also realize that out of all the languages available which may use OOP designs better, they are still not considered to be a true OOP language.

  • Misconception #2 – OOP Patterns Are A Waste of Time/Effort

WRONG!   The majority who say this are either unable to grasp the very reasoning of patterns in the first place, or believe that it’s something that should only be used in advanced programming languages (C++, Java, etc).  The truth is patterns can help your code, make it more scalable, and ultimately improve performance..but only if used properly.  Does that sound a bit hypocritical?  On the surface sure, but realize that this is true for literally everything in PHP.  One example would be my article about use of Recursive Methods: If you use the “improper” but perfectly valid method instead of recursion, you would actually decrease performance — even though the code was valid!

  • Misconception #3 – Creating Multiple Instances of an Object is Perfectly Fine

It’s very easy to think about OOP in this manner.   It just makes sense right?  What’s wrong with creating a new instance of an object whenever we want to use this object?  Why not just keep unsetting the object after we use it, and re-instantiate it when we need it?  WHO CARES?  This is a very dangerous misconception.  Why these sorts of things matter is every time an object is created, the entire object is stored in memory.  This is especially true since PHP passes by reference in OOP land (which means it keeps values and representations of your object/values/variables/methods/etc in a block of memory rather than creating a “copy” (as was true with PHP 4.x and below unless you use the infamous & operator).  It also will slow down performance since that object must be rebuilt from the ground up every time you create it.  This is true since it must reset any/all local scope properties, variables, definitions in order to be considered a true new instance.

With this small list of  misconceptions out of the way, let’s get into the meat of our discussion.

The Singleton Pattern

When one creates a class, it stems (or at least should be) from needing a way to reuse a “set” of methods in multiple applications.  One of the most common classes a developer or team of developers build is a Database Handler (dbh) object (we will use this as our main example throughout the rest of this article).

A very common thing we can see through the use of our object is it is instantiated (ie: $dbh = new myDBH();).  This is used throughout all of our applications each time we need a database connection opened to our MySQL server from application to application.

So say that we have 5 different applications that can be loaded independently on separate pages or simultaneously on the same page :

  • user management system – constantly keeps track of our user(s) that are logged into our system
  • navigation system –  loads sections based on the page we are on
  • page manager – loads the page content we are wanting to load
  • advertisement application – controls what ads are displayed when/where
  • schedule application – keeps track of what content is allowed to be displayed on each page.

At this point, you may be saying “TELL ME WHAT THE HELL IS WRONG WITH THIS ALREADY!!”.  Ok…chill out psycho and I’ll explain.

Assume that each one of these applications has a line in it that defines a variable, $dbh,  that holds an instance of an object, myDBH.  Each time that our object is instantiated, a new instance is created for that object which includes:

  • a new connection to MySQL (5 connections per user!!!)
  • a new block of memory taken up to hold all the changes of this object (5 blocks per user!!!)
  • all the classes that belong in the hierarchy (5 times these are also loaded per user!!!)

I think you get the picture already.  Myself, I never really considered why this was such a bad deal as I never knew a different way existed to keep this sort of thing from happening.  Singleton to the rescue!

What is a Singleton Pattern?

A “singleton pattern” is nothing more than a way to maintain one instance and state of an object at any given time.  This means that instead of creating our object 5 different times, we instead make a call that says “wait, this object has already been instantiated.  here, let me return to you the current active instance instead”.  Immediately, you should realize a point (which will be covered shortly) that the singleton pattern is not always the best solution.

Wikipedia describes the singleton pattern in the following verbage:

In computer engineering, the singleton pattern is a design pattern used to implement the mathematical concept of a singleton, by restricting the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects (say, five). Some consider it ananti-pattern, judging that it is overused, introduces unnecessary limitations in situations where a sole instance of a class is not actually required, and introduces global state into an application.

In C++ it also serves to isolate from the unpredictability of the order of dynamic initialization, returning control to the programmer.

But why not create the instance of our object inside of a file that is loaded via include_once?  I guess that depends on the developer, team, and how they think about flow and “cleanliness” of their code base.  To me, including a file simply to have one line of code that creates an instance is, well, a waste of a file and line of code.  I also personally believe that this is considered “sloppy code”.  But, I will stop myself there before this starts sounding like a rant or that I’m standing on a soap box and preaching my own personal view.

We also must keep in mind that we will need to check to make sure that $dbh was defined before we use it. Otherwise, we need to create the object. We also must keep track of our variable names and make sure $dbh isn’t being defined as something elsewhere ($dbh instanceof myDBH for example).  Otherwise, we run the risk of ruining another tool’s implementation of that variable name (note that this wouldn’t be possible if the company standard has been defined to make $dbh a variable that can only hold an instance of myDBH…but each company is different ;) ).

At the end of the day, I would challenge you to at least understand how we can use the singleton approach to “improve” this sort of thinking and then — decide for yourself.

Creating a Singleton Pattern

Creating a singleton object is quite simple;  so simple it can even be applied to existing objects with minimal code rewrites!

To better explain this approach, let’s consider that the following code is our myDBH class:

 "localhost", "dbname" => "myDB", "username" => "myDB_user", "password" => "myDB_password");
  public $dbh;

  public function __construct() {
    $this->dbh = new PDO("mysql:host={$this->db_info['host']};dbname={$this->db_info['db_name']}", $this->db_info['username'], $this->db_info['password'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
    $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
    $this->dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  }

  public function fetch_rows($sql) {
    $rst = $this->dbh->query($sql);
    return $rst->fetchAll();
  }

  public function fetch_row($sql) {
    $rst = $this->dbh->query($sql);
    return $rst->fetch();
  }
}
?>

Disclaimer: The above class is simple by design. It’s not a production-ready class, but merely something quick I want to use for our example.

Usage of this class would be something like this (assuming we are using autoload obviously…)

fetch_row("Select * from `mytable`");
// do some stuff...
?>

The above (as explained earlier) will create a new object every time we instantiate it, and create a new MySQL connection.

Now we want to implement a singleton solution. 2 questions come to mind:

  1. Do we want to maintain backwards compatibility, allowing us to update other scripts that may be using myDBH class at will?
  2. Do we just make the change and let any code that’s not updated break?

Those are questions you and your team should answer. If the answer to the first question to 1) is yes, then your construct will need to remain as it was prior to moving to the singleton pattern solution.   Realize that doing so would be considered more of a hybrid solution in that it allows us to have a singleton-like object, while still allowing the object to be instantiated normally.

So let’s look at both solutions.

Pure Singleton

 "localhost", "dbname" => "myDB", "username" => "myDB_user", "password" => "myDB_password");
  private $dbh;

  public static $instance = NULL;

  private function __construct(array $db_info = null) {
    if(isset($db_info)) {
      foreach($db_info as $key_name => $key_value) {
        if(!in_array($key_name, array("host", "db_name", "username", "password") || empty($key_value))) {
          throw new Exception("Invalid key passed!");
        }
        $this->db_info = $db_info;
      }
    }
    $this->dbh = new PDO("mysql:host={$this->db_info['host']};dbname={$this->db_info['db_name']}", $this->db_info['username'], $this->db_info['password'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
    $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
    $this->dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  }

  public static function getInstance() {
    if(!isset(self::$instance)) {
      self::$instance = new myDBH();
    }
    return self::$instance;
  }

  public function fetch_rows($sql) {
    $rst = $this->dbh->query($sql);
    return $rst->fetchAll();
  }

  public function fetch_row($sql) {
    $rst = $this->dbh->query($sql);
    return $rst->fetch();
  }
}
?>

Our new usage would look like this:

// Option 1
$dbh = myDBH::getInstance();
$rst = $dbh->fetch_row("Select * from `mytable`");

// Option 2 (Method Chaining Example)
$rst = myDBH::getInstance()->fetch_row("Select * from `mytable`");

Explanation of Our Changes

The first thing to note is the change in visibility of some the following:

  • The constructor changed from public to private (this prevents anyone from instantiating this object without explicitly calling getInstance)
  • The $dbh variable changed from public to private (this prevents any child from overriding the $dbh variable with anything other than the singleton’s definition)
  • The db_info array changed from public to private (same reasoning as $dbh)

The second thing to note is the 2 new additions:

  • public static $instance – holds the actual instantiated object of our myDBH class
  • public static getInstance() – This method first checks to determine if $instance is null. If it is, it will attempt to create an instance of myDBH and store it inside this variable. Finally, we return self::$instance (this is also done when self::$instance is not null!).

With the pure solution, we obtain an instance of our object via the static method getInstance instead of instantiating it normally via new object(). getInstance() will either create a new instance of our myDBH object (if has never been called before) or retrieve the existing instance (if  getInstance() has already been called) of our object!

Hybrid Singleton

 "localhost", "dbname" => "myDB", "username" => "myDB_user", "password" => "myDB_password");
  private $dbh;

  public static $instance = NULL;

  public function __construct(array $db_info = null) {
    if(isset($db_info)) {
      foreach($db_info as $key_name => $key_value) {
        if(!in_array($key_name, array("host", "db_name", "username", "password") || empty($key_value))) {
          throw new Exception("Invalid key passed!");
        }
        $this->db_info = $db_info;
      }
    }
    $this->dbh = new PDO("mysql:host={$this->db_info['host']};dbname={$this->db_info['db_name']}", $this->db_info['username'], $this->db_info['password'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
    $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
    $this->dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
  }

  public static function getInstance() {
    if(!isset(self::$instance)) {
      self::$instance = new myDBH();
    }
    return self::$instance;
  }

  public function fetch_rows($sql) {
    $rst = $this->dbh->query($sql);
    return $rst->fetchAll();
  }

  public function fetch_row($sql) {
    $rst = $this->dbh->query($sql);
    return $rst->fetch();
  }
}
?>

Our usage with the hybrid approach gives us three usages:

// Optioon 1 (Normal)
$dbh = new myDBH();
$rst = $dbh->fetch_row("Select * from `mytable`");

// Option 2 (Singleton)
$dbh = myDBH::getInstance();
$rst = $dbh->fetch_row("Select * from `mytable`");

// Option 3 (Singleton with Method Chaining Example)
$rst = myDBH::getInstance()->fetch_row("Select * from `mytable`");

Explanation of Our Changes

The first thing to note is the visibility differences with a hybrid solution:

  • The constructor remains public instead of private (this allows us to call our constructor normally and by getInstance())
  • The $dbh variable remains private (this, again, prevents ending children from overriding our dbh variable)
  • The db_info array changed from public to private (same reasoning as $dbh)

Our 2 new methods still remain:

  • public static $instance – holds the actual instantiated object of our myDBH class
  • public static getInstance() – This method first checks to determine if $instance is null. If it is, it will attempt to create an instance of myDBH and store it inside this variable. Finally, we return self::$instance (this is also done when self::$instance is not null!).

With the hybrid solution, we can use the class via getInstance or by calling it normally. However, this approach should be used only with the idea that deprecated implementations of our myDBH class exist only temporarily until we can upgrade all applications to use the singleton approach. All future implemenations should be using the singleton approach. Once all applications have been successfully upgraded to use the Pure Singleton usage, the class should also be updated to reflect this by changing the visibility of the object’s properties (explained above in “Pure Singleton”).

At this point, we now have what is called a “singleton object”.  We should also have a firm understanding of what a singleton really is.

Conclusion

I hope by now, you have a good, concrete understanding of what a “singleton pattern” is, and how it can be created.  Realize that a singleton is not always the best solution, nor is it the only pattern available for OOP.

Singleton’s should be created when an object is used over and over with no affect to applications that use it when the object’s environment changes.  To determine this, just ask yourself the following question: “If I create a variable (let’s call it $obj) to hold an instance of my class, and then I use that same variable with a totally different application on the same page , will anything break?”.  If the answer is no, then you may be a good candidate for a singleton pattern.

Singleton’s should not be used when you have a class that is state-dependent.  What this means is, if your object can hold values that are specific to that instance, then you should not use a singleton approach.  If this is not very clear, please ask and I’ll see if I can reword this or give some examples.

Finally, in order to encourage the idea of searching out other alternatives, I would recommend visiting Wikipedia’s Design Patterns.  These patterns are usually explained with languages other than PHP, but this is a good thing!   OOP is OOP – regardless as to what language it is used in.  The syntax may be different but the general concept will remain.  The point is to encourage searching out how OOP is being used, thereby reducing redundant discovery into these areas.

Good luck!

Resources

Special Thanks

A special thanks goes out to Chris Cember for spending the time to give me some really helpful pointers to making this a more structured article.  Also, thanks to William Wade for his suggestions (along with Chris’) to see examples of the hybrid approach.

Leave a Reply