Blog RSS Feed Subscribe

Jordi Boggiano

Jordi Boggiano Passionate web developer, specialized in web performance and php. Partner at Nelmio, information junkie and speaker.

Categories

Multiton base class

While I like the Singleton pattern every now and then, I prefer the flexibility that the Multiton potentially offers, and well it's just an extended version of the Singleton, so it's "compatible" with the Singleton model.

Anyway, to the point, PHP5.3 is coming, and with Late Static Binding you can do a base Multiton (or Singleton if you insist), which wasn't possible before. Now I like this very much because you can simply extend it rather than rewriting those (few, I know, but still) lines each time.

<?php 
  
class Multiton 
{ 
    protected static $instances; 
    
    final protected function __construct() {} 
    
    public static function getInstance($id = '') 
    { 
        $class = get_called_class(); 
        if (!isset(self::$instances[$class][$id])) { 
            self::$instances[$class][$id] = new $class; 
        } 
        return self::$instances[$class][$id]; 
    } 
    
    public static function initInstance($id, $object) 
    { 
        $class = get_called_class(); 
        self::$instances[$class][$id] = $object; 
    } 
}

So, this class features the getInstance() method, and an initInstance() method that can be used to inject a specific instance of a different class, for unit testing requirements for example. It might be bad practice though, I'm not sure and can't find Sebastian "PHPUnit" Bergmann on irc at the moment, so please yell at me if you think this is stupid.

And now here's some example code and output to prove that it works, although I could have faked it..

<?php 
  
class Test extends Multiton 
{ 
} 
  
$a = Multiton::getInstance(); 
$a->foo = 'bar'; 
$b = Test::getInstance(); // you can use it as a Singleton 
$b->foo = 'baz'; 
$c = Test::getInstance('foo'); // or as a Multiton with an id for each object 
$c->foo = 'qux'; 
  
var_dump($a,$b,$c); 
  
/* outputs : 
  
object(Multiton)#1 (1) { 
  ["foo"]=> string(3) "bar" 
} 
object(Test)#2 (1) { 
  ["foo"]=> string(3) "baz" 
} 
object(Test)#3 (1) { 
  ["foo"]=> string(3) "qux" 
} 
  
*/ 
  
// instantiation fails correctly.. nothing new there 
new Test(); // Fatal error: Call to private Multiton::__construct() from invalid context

So this is not life changing I guess, but it's one more reason to switch to 5.3 once it is available.

December 23, 2008 // PHP

Post a comment:


Formatting: you may use [code php] [/code] (or other languages) for code blocks, links are automatically linked. <strong>, <em> and <blockquote> html tags are allowed without nesting, the rest will be escaped.

Subscribe to this RSS Feed Comments

2008-12-23 09:12:23

SchizoDuckie

Actually, i'm already using this pattern for my database class. Works perfect (also in < 5.3 ofcourse) if you need for example a mysql ánd an sqlite connection. Cant wait for 5.3 :-)

2008-12-23 09:38:12

Žilvinas

Can you share how are you doing this pre 5.3 SchizoDuckie ?

2008-12-23 09:51:09

Les

A singleton is still a singleton even after you've dressed it up, as is the case here.

Remember, design patterns are not set in stone but are flexible approaches to solving a given problem. So this in my mind is STILL a singleton.

Merry Xmas by the way, peace be with us all.

2008-12-23 14:48:40

Seld

@SchizoDuckie yup, it's nothing new, 5.3 just allows you to do extend it while keeping the functionality.

@Les well it is a singleton, but it's a bit more than the stock singleton implementation so why not give it another name ?

2008-12-23 17:33:31

Justin

One way to 'fake' this behavior is to have a protected member var (not static) like protected $thisClassName - and use that instead of get_called_class() above.  Yeah, its one line of code you have to put in each class, but its a somewhat simpler one than the whole getInstance function.

Anyway, can't wait for 5.3!

2008-12-23 17:34:29

Justin

Oh, i've called this pattern a 'Groupleton' before.  It sounds funnier.

2008-12-23 17:37:37

Hodicska Gegely

Don't forget __clone()! ;)

2008-12-30 23:49:27

Andrew Johnstone

This is the first I've heard of Multiton, how does this differ from a registry?

2008-12-31 02:10:23

Seld

@Andrew well.. it's sort of a local registry I guess. A registry is an extended multiton in the sense that it can hold multiple instances of multiple classes, while the multiton is only from one class. Anyway it's all semantics.. and that doesn't matter as much as what you gain from using this or that pattern.

I just wanted to point out a new possible way of doing that in 5.3.