Although Multiton is regarded by many just as another type of Singleton and not even a design pattern by itself, I like to give it the credits it deserves and put it next to it’s little brother on the same rank of importance in the world of design patterns.

Anyway, one thing is clear: it resembles so much the Singleton pattern that in all the technical books you will always find it explained right next to this one. Some books, like Addison-Wesley’s “Design Patterns” refer to it as “Registry of Singletons” instead of Multiton.

You already probably know what a Singleton is (if not I advise you to read this article first, where I explained what’s a Singleton and where you should use it), so let’s see what new things Multiton comes with.

In my previous article I was saying that the most common situation when you would implement a Singleton is when you want to create a connector to the DB. Let’s rewrite that previous example and add it a little “final” touch :)

final class Singleton {
    private static $_instance = null;

    private function __construct()
    {
    }

    public static function getInstance()
    {
        if (is_null(self::$_instance)) {
            self::$_instance = new Singleton();
        }

        return self::$_instance;
    }
}

This means that my class is final so therefore it may not be extended by any other class. That’s also why I removed the “final” keyword I previously had in front of the constructor. If my entire class is marked as final there’s no reason why I should explicitly mark my constructor as final also.

Now for clarity reasons let’s rename our class from Singleton to DB (because it’s a DB connector after all) and add some code so that it will look like something functional.

final class DB {
    private static $_instance = null;

    private $__db_handler;

    private function __construct()
    {
        $this->__db_handler = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
    }

    final public function __destruct()
    {
        $this->__db_handler->close();
    }

    public static function getInstance()
    {
        if (is_null(self::$_instance)) {
            self::$_instance = new DB();
        }

        return self::$_instance;
    }
}

That’s more like it! Nice, clean and it also looks pretty functional and clear. You can take a step back and while you admire it imagine you have a whole bunch of other pretty methods around there.

So now let’s assume you are asked to build a simple module to your application that will have to connect to a different DB and just build up some statistics. You already have the DB connector written and reusing the code is one of the many advantages that OOP gives us. But wait: that instance of the Singleton will always connect to the same DB because you don’t provide the connection details from outside and the class can’t be extended anymore. Oh crap!

This means that your only choice will be to duplicate your code which is clearly out of the question because you are a smart guy! Or… you could use a Multiton or a Registry of Singletons (more about the Registry pattern in a future article).

Basically, the major difference between a Singleton and a Multiton is that a Singleton will allow you to have only one single instance of that class per application, while a Multiton will allow you to have one single instance per key (a key is actually a set of data you provide from the outside when you get the instance).

In other words, a Multiton will allow some parameters to be passed to the getInstance() method and based on those parameters it will always give you that same object. For example Multiton::getInstance(‘banana’) will always give you {Instance1}, and Multiton::getInstance(‘apple’) will always give you {Instance2}.

This is the skeleton for a generic class that implements the Multiton pattern:

final class Multiton {
    private static $_instances = array();

    private $_details;

    private function __construct($_details)
    {
        $this->_details = $_details;
    }

    public static function getInstance($_details)
    {
        $_key = md5(serialize($_details));

        if (!isset(self::$_instances[$_key])) {
            self::$_instances[$_key] = new Multiton($_details);
        }

        return self::$_instances[$_key];
    }

    public function getDetails()
    {
        return $this->_details;
    }
}

In our case, the DB connector would look something like:

final class DB {
    private static $_instances = array();

    private $__db_handler;

    private $_details;

    private function __construct($_db_host, $_db_user, $_db_pass, $_db_name)
    {
        $this->__db_handler = new mysqli($_db_host, $_db_user, $_db_pass, $_db_name);
        $this->_details = array($_db_host, $_db_user, $_db_pass, $_db_name);
    }

    public function __destruct()
    {
        $this->__db_handler->close();
    }

    public static function getInstance($_db_host, $_db_user, $_db_pass, $_db_name)
    {
        $_key = md5($_db_host . $_db_user . $_db_pass . $_db_name);

        if (!isset(self::$_instances[$_key])) {
            self::$_instances[$_key] = new DB($_db_host, $_db_user, $_db_pass, $_db_name);
        }

        return self::$_instances[$_key];
    }

    public function getDetails()
    {
        return $this->_details;
    }
}

This way, your models from the application will have their own credentials, while you can still make thousands of modules or plugins with different connection details and reuse the same object seamlessly.

«