Un singleton en PHP5
POO et PHP5
PHP5 apporte de nouvelles fonctionnalités dans le cadre de la POO, nous allons en utiliser quelques unes dans le cadre de la mise en place du « design pattern » singleton.
Le singleton est un « design pattern » - c'est à dire un « patron de conception » ou pour simplifier c'est une structure typique répondant à un impératif de développement - dans le cas du singleton, on souhaite créer une classe dont au plus une instance existera dans le script.
Par exemple dans le cadre d'une classe d'accès a une base de données, on peut souhaiter vouloir préserver l'unicité de la connexion tout au long du script. Une solution possible est d'initialiser l'objet de connexion en début de script, de stocker une référence sur l'objet dans un variable globale, et d'accéder à celle-ci à chaque fois que l'on souhaite accéder a la base de données. On pourra aussi passer cette référence à chaque « module » qui est susceptible de d'utiliser cette objet d'accès à la base de données.
PHP5, par opposition à PHP4 nous fourni de quoi faire ceci de manière élégante.
Private
PHP5 gère la visibilité des propriétés et des méthodes, ainsi dans:
<?php
class Ooops {
private $plouf;
private function ding() {
...
}
}
?>
La propriété $plouf de la classe Ooops est définie comme private et donc ne sera accessible que depuis la classe elle même, ainsi que la méthode ding().
<?php
$instance = new Ooops;
$instance->ding();
?>
Renverra donc une erreur
Fatal error: Call to private method Ooops::ding() from context '' in
Static
PHP5 gère aussi les éléments static dans les classes. C'est à dire que l'élément sera uniquement dépendant de la classe elle-même et non pas de ses instances. Dans le cadre d'une méthode static il est bien entendu impossible d'utiliser le mot clef $this se rapportant à l'objet, étant donnée que la propriété est indépendante de celui-ci.
<?php
class Ooops {
static $paf = 4;
static function dong() {
return self::$paf * 2; // le mot clef self appelle la classe courante
}
}
Ooops::$paf = 8;
echo Ooops::$paf; // renvoi 8;
echo Ooops::dong(); // renvoi 16;
$instance = new Ooops;
echo $instance->dong(); // permet aussi d'accéder a la méthode static
?>
La structure du singleton
La classe que nous allons construire ne devrait pas être instanciable par la méthode classique new. Une solution est de déclarer le constructeur de la classe comme private, ainsi toute construction d'une instance depuis l'extérieur de la classe renverra une erreur: Fatal error: Call to private Single::__construct() from context '' .
<?php
Class Single {
private function __construct() {
...
}
}
?>
Elle doit stocker l'instance unique de la classe dans une variable pour pouvoir la transmettre à d'autres éléments du script. Cette variable ne doit pas dépendre de l'instance, on déclarera donc une variable static à cet effet.
<?php
Class Single {
static $instance;
private function __construct() {
...
}
}
?>
La récupération de l'instance courante
Enfin la classe doit proposer une méthode accessible en dehors d'une instance permettant de renvoyer l'instance unique existante, ou créant celle-ci. Cette méthode sera aussi déclaré comme static étant donnée qu'elle doit être disponible avant l'existence de l'instance.
<?php
Class Single {
static $instance;
private function __construct() {
...
}
static function GetInstance() {
if (empty(self::$MyInstance)) {
self::$MyInstance = new Single;
}
return self::$MyInstance;
}
}
?>
Lors du premier appel, GetInstance crée une nouvelle instance et la stocke dans Single::$instance, lors des appels suivants elle renverra Single::$instance.
Le fonctionnement
Au lieu d'instancier la classe Single à chaque fois que vous en avez besoin, il suffit d'appeler Single::GetInstance() pour récupérer l'objet courant et s'en servir comme n'importe quel objet.
<?php
$MonObjet = Single::GetInstance();
$MonObjet-> MaMethode();
?>
Dans PHP4 les objet été transmis par copie, $O = $A, faisait que $O était une copie de $A et pouvait alors poursuivre sa vie indépendamment de $A, On pouvait modifier se comportement en utilisant l'opérateur & qui permettait de transmettre les objet par référence. Ainsi $O = & $A, ne créait pas un second objet mais rendait accessible le contenu de $A en utilisant $O.
Ainsi $MonObjet est une référence sur l'objet unique instancié dans la méthode GetInstance().
Exemples d'utilisation possible.
Le principal intérêt, assurer l'unicité d'un objet. Dans le cadre de l'accès a une base de donnée, ou de connexion par socket, on peut s'en servir pour utiliser une connexion unique.
Un autre intérêt est d'assurer un accès facile à l'instance quelques soit la profondeur du code et pour éviter d'avoir à passer l'objet en cascade à tous les objets susceptibles de l'utiliser.