Multitons in PHP

In my last blog I covered the singleton design pattern (DP), showing how and when to use it. In this article I am going to cover a very similar design pattern called the multiton.

A multiton is almost exactly the same as a singleton, the one slight difference is a multiton can store multiple instances of itself. Contrary to a singleton, which can only store one instance of itself.

When to use a multiton

The ideal use for a multiton is when you need to create multiple instances of a particular class and you want to store references to each instance. This is most useful when you’re only creating a small amount of the class in question and you want to access different instances in different parts of your code. I’m going to use a database example again, solely because it’s the best real world use case. If you start creating more than 5-10 instance of a multiton, than you probably shouldn’t be using a multiton and rather storing the objects in a dependency injection container (DIC). Multitons are only for creating a small collection of objects.

Rules when creating a multiton

  1. Just like a singleton, multitons should have a private __construct() method. Instances should be created using a static getInstance() method.
  2. Each instance of the multiton which is created should be stored inside a static $instances attribute
  3. When the getInstance() method is called a value should be passed as the only argument, this value should be used as the key when storing the instance inside the $instances attribute.
  4. To retrieve an existing instance, the name of the instance you want to retrieve should be passed to the getInstance() method, which will return the pre-initialised instance, instead of creating a new instance.

Drawbacks

For full details on the drawback you should check out the article I wrote on singletons, as they have the same problems. But here is a quick summary.

  1. Multitons add dependencies to your code because the are called globally.
  2. They are hard to test because of their use of static methods and attributes.

Code Example

class Database {

    /**
     * Used to store and provide instances for the getInstance() method
     */ 
    private static $instances = array();

    /**
     * Hidden constructor, only callable from within this class
     */
    private function __construct() { }

    /**
     * Create a new instance if one doesn't exist with the key provided.
     * Once an instance has been created, or if it was already created, return it.
     * @param $key the key which the instance should be stored/retrieved
     * @return self
     */
    public static function getInstance($key) {

        // Check if an instance exists with this key already
        if(!array_key_exists($key, self::$instances)) {
            // instance doesn't exist yet, so create it
            self::$instances[$key] = new self();
        }

        // Return the correct instance of this class
        return self::$instances[$key];
    }

    /**
     * Hidden magic clone method, make sure no instances of this class 
     * can be cloned using the clone keyword
     */
    private function __clone() { }
    
}

// Create first instance to the master database
$master = Database::getInstance('master');
var_dump($master); // object(Database)#1 (0) { }

// Create second instance of this class for a logger database
$logger = Database::getInstance('logger');
var_dump($logger); // object(Database)#2 (0) { }

// Retrieve the existing 'master' instance from the multiton
// this would normally be done in script, which doesn't have the instance already
$masterDupe = Database::getInstance('master');
var_dump($masterDupe); // object(Database)#1 (0) { }

// Database objects cannot be initialise with the new keyword, doing so will cause fatal errors
// Fatal error: Call to private Database::__construct() from invalid context
$dbFatalError = new Database();

// Database objects cannot be cloned, doing so will cause a fatal error
// PHP Fatal error:  Call to private Database::__clone()
$dbCloneError = clone $masterDupe;
17 Love This

3 Comments Multitons in PHP

  1. Pingback: My Homepage

    1. Simon

      Sure, are you looking for a PHP solution? You can use a popular dependency injection container like Pimple or the Symfony DependencyInjection component.

      Reply

Leave a Reply

Your email address will not be published.