Durante uma discussão hoje na lista php-especialistas, eu criei um protótipo para a implementação do padrão Singleton, mas que (na minha opinião) acabou ficando bem legal… Então, para não desperdiçar o trabalho e movimentar um pouco o blog, segue o código abaixo:
<?php
abstract class Singleton {
static private $instance = array();
final static public function instance($module) {
if (!class_exists($module))
throw new Exception("Module '{$module}' not found.");
$module = strtolower($module);
if (!isset(self::$instance[$module]))
self::$instance[$module] = new $module;
return self::$instance[$module];
}
}
?>
Quer saber como ela funciona!? Essa classe abstrata, portanto não pode ser instanciada, funciona da seguitne forma: sempre que você quiser que uma determinada classe siga ao padrão Singleton, basta chama-la sempre através da classe acima, como segue:
<?php
require_once 'Singleton.php';
class ClassA {
public $valueA = null;
}
class ClassB {
public $valueB = null;
}
try {
$objA1 = Singleton::instance('ClassA');
$objA2 = Singleton::instance('ClassA');
$objA1->valueA = 'ClassA instance 1';
echo $objA2->valueA . "\n";
$objB1 = Singleton::instance('ClassB');
$objB2 = Singleton::instance('ClassB');
$objB1->valueB = 'ClassB instance 1';
echo $objB2->valueB . "\n";
$objC1 = Singleton::instance('ClassC'); // exception!
} catch (Exception $ex) {
echo "<b>Singleton Error:</b> {$ex->getMessage()}";
}
?>
E o resultado do código acima é:
ClassA instance 1 ClassB instance 1 Singleton Error: Module 'ClassC' not found.
E é isso ae, espero que esse código seja útil para mais alugém. :)
UPDATE1: Definido o método Singleton::instance como final, assim ele não poderá ser alterado por nenhuma classe que extenda a classe Singleton.
UPDATE2: Na versão 5.3 do PHP, foi introduzida uma funcionalidade chamada de Late static binding que faz com que possamos criar (sem nenhuma artimanha-extravagante) uma classe Singleton, onde todas as classes que a extenderem serão Singleton também. Algo parecido com o código abaixo.
<?php
require_once 'Singleton.php';
abstract class Singleton {
static private $__CLASS__ = __CLASS__;
static private $instance = null;
final static public function instance() {
if (static::$instance == null)
static::$instance = new static::$__CLASS__;
return static::$instance;
}
}
?>
E nessa caso, a implementação fica algo mais ou menos parecido com:
<?php
class ClassA extends Singleton {
// Singleton implementation
static private $__CLASS__ = __CLASS__;
static private $instance = null;
prublic $value = null;
}
$objA1 = ClassA::instance();
$objA2 = ClassA::instance();
$objA1->value = 'ClassA instance 1';
echo $objA2->value . "\n";
?>
Nessa versão 5.3, ainda dará para usar os namespaces organizando um pouco melhor essa estrutura. :)


