200 likes | 330 Views
Bases de données Objet singleton pour la connexion. Problème posé. Développement d'un site nécessitant une BD : Connexion en début de chaque page PHP Requête(s) Déconnexion en fin de programme PHP Développement objet d'un site avec une BD : Connexion dès que la BD est utilisée
E N D
Bases de donnéesObjet singleton pour la connexion Programmation Web 2012-2013
Problème posé • Développement d'un site nécessitant une BD : • Connexion en début de chaque page PHP • Requête(s) • Déconnexion en fin de programme PHP • Développement objet d'un site avec une BD : • Connexion dès que la BD est utilisée • Requête(s) à divers endroits dans les diverses méthodes des diverses classes • Déconnexion quand la BD n’est plus utile Quand doit-on se connecter, se déconnecter ? Programmation Web 2012-2013
Solution : patron de conception Singleton • Singleton : objet à instance uniqueInstance unique pour gérer une connexion BD unique • Réalisation : • 1 attribut statique • Instance • 1 point d'accès • méthode statique • limiter l'accès au constructeur • privé / protégé • interdire le clonage Programmation Web 2012-2013
Singleton : Illustration du fonctionnement <?phpclass Singleton {privatestatic$_instance=null ; public $attr=null ; publicstaticfunction getInstance(){if(!self::$_instanceinstanceofself){self::$_instance=newself() ;}returnself::$_instance ;}}$i1= Singleton::getInstance() ;$i2= Singleton::getInstance() ;$i3= Singleton::getInstance() ;$i1->attr ="ours" ; $i3->attr=42 ;echo$i2->attr ; Classe Singleton getInstance() $_instance null $i1 Instance Singleton $i2 $attr $i3 "ours" 42 null Programmation Web 2012-2013
Solution : patron de conception Singleton • Adaptation à la connexion BD : Connexion • 1 attribut statique • instance • 1 attribut de l’instance • Ressource BD • 1 point d'accès • Méthode statique requete • constructeur privé • établit la connexion à la BD • destructeur • termine la connexion à la BD • mise hors service de la méthode __clone • private ET throw new Exception("…") ; Programmation Web 2012-2013
Durée de vie de l'objet Connexion • Nature de l'objet • membre statique d'une classe ≈ variable globale • Construction • créé au premier appel de Connexion::requete() • Destruction • variable globale : durée de vie = le programme • détruit automatiquement en fin de script • Bilan : • connexion automatique lors de la première requête • déconnexion automatique à la fin du script • facile, propre et transparent pour le développeur Programmation Web 2012-2013
Raffinement possible : Débogage • possibilité de collecter des messages informatifs pour se rendre compte de ce qu'il se passe et dépister les erreurs : • connexion… • requête… • Cadre Web : • ne pas perturber la page : commentaires HTML • doit pouvoir être désactivé contenu des images • Implémentation : • attribut booléen statique et méthodes statiques • utilisation d’un singleton de collecte d’informations Programmation Web 2012-2013
Une implémentation /// Singleton permettant d'effectuer une connexion unique à la BD class Connexion { // Paramètres de connexion à la base de données privatestatic$_host=null ; /// HôteMySQL privatestatic$_user=null ; /// Utilisateur MySQL privatestatic$_passwd=null ; /// Mot de passe MySQL privatestatic$_base=null ; /// Base de données de travail // Gestion de l'instance unique privatestatic$_instance=null ; /// Objet Connexion // Traces d'exécution privatestatic$_traces=true ; /// Débogage actif ou non // Attribut de l'objet : ressource de la connexion à la base de données private$_ressourceBD=null ; /// Connexion à la base Programmation Web 2012-2013
Une implémentation /// Constructeur privé privatefunction__construct(){ self::msg("Construction de l'objet Connexion...") ; // Vérifier la présence des paramètres de connexion if(is_null(self::$_host) ||is_null(self::$_user) ||is_null(self::$_passwd) ||is_null(self::$_base)) thrownewException("Connexion impossible : les paramètres de connexion sont absents") ; // Etablir la connexion if(!($tmp= @mysql_connect(self::$_host, self::$_user, self::$_passwd))) thrownewException("Connexion impossible à la base de données") ; $this->_ressourceBD=$tmp ; Programmation Web 2012-2013
Une implémentation // Sélectionner la base de donnees if(! @mysql_select_db(self::$_base, $this->_ressourceBD)) thrownewException("Sélection de la base impossible : " .mysql_error($this->_ressourceBD)) ; // Mise en place de la table de caractères mysql_query("SET CHARACTER SET 'utf8'", $this->_ressourceBD) ; self::msg("Construction terminée") ; } Programmation Web 2012-2013
Une implémentation /// Destructeur publicfunction__destruct(){ self::msg("Demande de destruction de l'objet Connexion...") ; // S'il y a une connexion établie... if(!is_null($this->_ressourceBD)){ // ... il faut se déconnecter self::msg("Demande de déconnexion...") ; mysql_close($this->_ressourceBD) ; $this->_ressourceBD=null ; self::$_instance=null ; self::msg("Déconnexion effectuée") ; } self::msg("Destruction terminée") ; // Affichage des traces si le Débogage est actif if(self::$_traces){ echoTraceur::affiche() ; } } Programmation Web 2012-2013
Une implémentation /// Accesseur à l'instance qui sera créée si nécessaire privatefunctiondonneInstance(){ self::msg("Recherche de l'instance...") ; // Existe-t-il une instance de Connexion ? if(is_null(self::$_instance)){ // NON : il faut en créer une self::$_instance=newConnexion() ; } self::msg("Instance trouvée") ; returnself::$_instance ; } /// Accesseur à la connexion à la base de données privatestaticfunctiondonneRessourceBD(){ self::msg("Recherche de la ressource BD...") ; returnself::donneInstance()->_ressourceBD ; } Programmation Web 2012-2013
Une implémentation /// Fixer les paramètres de connexion publicstaticfunctionparametres($host, $user, $passwd, $base, $traces){ self::debogage($traces) ; self::msg( "Demande de positionnement des paramètres de connexion...") ; self::$_host=$host ; self::$_user=$user ; self::$_passwd=$passwd ; self::$_base=$base ; self::msg("Positionnement des paramètres de connexion terminé") ; } Programmation Web 2012-2013
Une implémentation /// Effectuer une requête et retourner le résultat publicstaticfunctionrequete($req){ self::msg("Demande d'exécution de la requête:\n$req") ; $res= @mysql_query($req, self::donneRessourceBD()) ; if($res===false){ thrownewException("Erreur pour la requête '{$req}' : " .mysql_error(self::donneRessourceBD())) ; } self::msg("Requête effectuée") ; return$res ; } Programmation Web 2012-2013
Une implémentation /// Protéger une chaîne de caractères avant de l'intégrer dans une requête publicstaticfunctionprotectionChaine($chaine){ self::msg("Protection de la chaine '{$chaine}'") ; returnmysql_real_escape_string($chaine, self::donneRessourceBD()) ; } /// Retouner le nombre d'enregistrements affectes publicstaticfunctionnombreLignesAffectees(){ returnmysql_affected_rows(self::donneRessourceBD()) ; } /// Interdire le clonage privatefunction__clone(){ thrownewException("Clonage de ".__CLASS__." interdit !") ; } Programmation Web 2012-2013
Une implémentation /// Collecte de messages de contrôle staticfunctionmsg($message){ if(self::$_traces) Traceur::trace($message) ; } /// Mise en marche ou arrêt des messages de contrôle staticfunctiondebogage($etat){ self::$_traces=(bool)$etat ; } } Programmation Web 2012-2013
Une implémentation - Débogage /// Singleton permettant de collecter des messages informatifs class Traceur { // Gestion de l'instance unique privatestatic$_instance=null ; /// Objet Traceur // Atttributs de l'objet private$_messages=array() ; /// Tableau des messages private$_temps=null ; /// Instant de création /// Constructeur privé privatefunction__construct(){ $this->_temps=microtime(true) ; } /// Interdire le clonage privatefunction__clone(){ thrownewException("Clonage de ".__CLASS__."interdit !") ; } Programmation Web 2012-2013
Une implémentation - Débogage /// Accesseur à l'instance qui sera créée si nécessaire privatestaticfunctiondonneInstance(){ if(is_null(self::$_instance)){ self::$_instance=newself() ; } returnself::$_instance ; } /// Méthode statique de collecte de messages publicstaticfunction trace($msg){ $instance=self::donneInstance() ; $instance->messages[]=$instance->duree(). " secondes : " .$msg ; } Programmation Web 2012-2013
Une implémentation - Débogage /// Calcul du temps écoulé depuis la création du traceur privatefunctionduree(){ returnnumber_format(microtime(true)-$this->_temps, 4) ; } /// Méthode statique d'affichage des messages collectés publicstaticfunction affiche($avant= "<!--", $apres= "-->"){ $messages=self::donneInstance()->messages ; $traces=null ; if(count($messages)){ $traces.="{$avant}\n" ; foreach($messagesas$m){ $traces.= "{$m}\n" ; } $traces.= "{$apres}\n" ; } return$traces ; } } Programmation Web 2012-2013
Utilisation require_once "connexion.mysql.template.class.php" ; Connexion::parametres('serveur', 'utilisateur', 'motdepasse', 'basededonees', true) ; // Exemple d'utilisation : $res=Connexion::requete(<<<SQL SELECTun_champ FROMune_table ORBER BY1 SQL ) ; while($ligne=mysql_fetch_assoc($res)){ /* ... */ $ligne['un_champ'] /* ... */ ; } Simple, non ? Programmation Web 2012-2013