Présentation
Le design pattern Singleton est un patron de conception de création d’objet. Il impose qu’une classe n’est qu’une seule instance possible et pas plus d’une et fourni un accès faisant systématiquement référence et cette instance unique.
Pour cela, il y a plusieurs étapes à respecter :
- Le constructeur de la classe devra être soit privé soit protégé (
privateouprotected). Ainsi, il ne sera plus possible de créer d’instance de cette classe avec le mot-clénew. - On crée donc une méthode statique à l’intérieur de la la classe dont le but sera de créer une instance de la classe elle-même. Pour s’assurer qu’il n’y ait qu’une instance possible de la classe, on stockera l’instance créée dans un attribut statique de la classe et si celui-ci existe, la méthode le retournera plutôt que de créer une nouvelle instance.
- Enfin, pour être vraiment certain de n’avoir qu’une instance possible de notre classe, nous allons interdire l’accès aux méthodes
__clone(),__sleep()et__wakeup().
Implémentation via l’héritage
Pour éviter de recoder ces comportements dans chaque classe devant être un singleton, on peut créer une classe Singleton dont hériteront chacune des classes devant être des singletons.
// Classe qui est un singleton
class MonSingleton
{
// Contiendra l'instance de la classe
protected static $instance;
// Constructeur en privé
protected function __construct() { }
// Méthode de clonage en privé pour interdire son usage
protected function __clone() { }
// Méthode qui créée et retourne l'instance unique
public static function getInstance()
{
// Si on n'a pas encore instancié notre classe
if (!isset(self::$instance)) {
// On l'instancie
self::$instance = new self;
}
return self::$instance;
}
}
// Usage dans les autres scripts PHP
$obj = MonSingleton::getInstance();Héritage ou trait ?
Le pattern Singleton est historiquement souvent implémenté via une classe dont on fait ensuite hériter de multiples objets. C’est le comportement décrit précédemment. Or, l’héritage multiple n’étant pas possible, cela peut poser des problèmes de conception. En effet, on se retrouve souvent confronter à un problème car on souhaiterait pouvoir faire hériter un objet d’un autre mais celui-ci hérite déjà de la classe Singleton.
Il vaut mieux privilégier l’héritage fonctionnel, ayant un réel sens. Le pattern Singleton devrait donc plutôt être implémenté via un trait depuis que cela est possible en PHP 5.4.
trait Singleton
{
protected static $instance = null;
public static function getInstance()
{
if ($this->instance === null) {
$this->instance = new self;
}
return $this->instance;
}
// Interdit d'instancier un objet via le mot-clé new
protected function __construct() { };
// Interdit le clônage de l'objet
protected function __clone() { }
// Interdit la sérialisation de l'instance de l'objet
protected function __sleep() { }
// Interdit la désérialisation de l'instance de l'objet
protected function __wakeup() { }
}
class MaClasse extends MaClassePrincipale
{
use Singleton;
}
$var = MaClasse::getInstance();