Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parClairene Pillet Modifié depuis plus de 10 années
1
Bases de données Objet singleton pour la connexion
01:08:06 Programmation Web
2
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 chaque page PHP Développement objet d'un site avec une BD : Connexions à divers endroits dans les méthodes Requête(s) à divers endroits dans les méthodes Déconnexion en fin de page PHP Quand doit-on se connecter, se déconnecter ? 01:08:06 Programmation Web
3
Singleton : objet à instance unique Réalisation :
Solution : Singleton Singleton : objet à instance unique Réalisation : 1 attribut statique Singleton 1 point d'accès méthode statique limiter l'accès au constructeur privé / protégé interdire le clonage 01:08:06 Programmation Web
4
Solution : Singleton Adaptation à la connexion BD PDO : myPDO
1 attribut statique mypdo Ressource BD = objet PDO 1 point d'accès Méthode statique get() constructeur privé établit la connexion à la BD destructeur termine la connexion à la BD mise hors service de la méthode __clone throw new Exception("…") ; 01:08:06 Programmation Web
5
Durée de vie de l'objet myPDO
Nature de l'objet membre statique d'une classe : variable globale Construction créé au premier appel de myPDO::get() Destruction variable globale : durée de vie = le script détruit en fin de script Bilan : connexion lors de la première requête déconnexion à la fin du script fonctionnement propre, transparent pour l'utilisateur 01:08:06 Programmation Web
6
Une implémentation <?php
/// Classe permettant de faire une connexion unique et automatique à la BD final class myPDO { /// Singleton private static $mypdo = null ; /// Message de debogage private static $debug = true ; /// Data Source Name private static $dsn = null ; /// Utilisateur private static $user = null ; /// Mot de passe private static $pass = null ; /// Connexion à la base private $pdo = null ; 01:08:06 Programmation Web
7
Une implémentation /// Constructeur privé
private function __construct() { self::msg("Demande construction PDO...") ; if ( is_null(self::$dsn) || is_null(self::$user) || is_null(self::$pass)) throw new Exception("Construction impossible : les paramètres de connexion sont absents") ; // Etablir la connexion $this->pdo = new PDO(self::$dsn, self::$user, self::$pass) ; // Mise en place du mode "Exception" pour les erreurs PDO $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ; self::msg("Construction PDO terminée") ; } 01:08:06 Programmation Web
8
Une implémentation /// Destructeur public function __destruct() {
self::msg("Demande de destruction PDO...") ; // S'il y a une connexion établie... if (!is_null($this->pdo)) { // ... il faut se deconnecter self::msg("Demande de déconnexion...") ; $this->pdo = null ; self::$mypdo = null ; self::msg("Deconnexion effectuée") ; } self::msg("Destruction PDO terminée") ; } 01:08:06 Programmation Web
9
Une implémentation /// Récupérer le singleton
public static function donneInstance() { self::msg("Recherche de l'instance...") ; // Une instance est-elle disponible ? if (!isset(self::$mypdo)) self::$mypdo = new myPDO() ; self::msg("Instance trouvée") ; return self::$mypdo->pdo ; } /// Fixer les paramètres de connexion public static function parametres($_dsn, $_user, $_pass) { self::$dsn = $_dsn ; self::$user = $_user ; self::$pass = $_pass ; 01:08:06 Programmation Web
10
Une implémentation /// Interdit le clonage du singleton
public function __clone() { throw new Exception("Clonage de ".__CLASS__." interdit !") ; } 01:08:06 Programmation Web
11
Simple, non ? Utilisation
require_once "connexion.pdo.template.class.php" ; // Paramétrage du singleton myPDO::parametres('oci:dbname=bd11', 'scott', 'tiger') ; // Connexion automatique $pdostat = myPDO::donneInstance()->query( "SELECT * FROM Images") ; while (($ligne = $pdostat->fetch()) !== false) { echo $ligne['id']."<br>\n" ; } // Déconnexion automatique en fin de script Simple, non ? 01:08:06 Programmation Web
12
Raffinement possible : Débogage
Possibilité d'afficher des messages informatifs pour se rendre compte de ce qu'il se passe et dépister les erreurs : connexion… requête… Cadre Web : comment afficher des informations qui ne perturbent pas l'affichage de la page commentaires HTML <!-- … --> doit pouvoir être désactivé contenus non HTML Implémentation : attribut booléen statique et méthodes statiques 01:08:06 Programmation Web
13
Raffinement possible : Débogage
Problème majeur, les méthodes de requête, préparation, etc sont des méthodes de l'objet PDO et non de myPDO Solution basique la méthode get retourne l'objet myPDO et non PDO l'objet myPDO doit implémenter toutes les méthodes de PDO qui consistent à lancer celles de PDO Solution "avancée" la méthode get() retourne l'objet myPDO et non PDO myPDO doit implémenter __call 01:08:06 Programmation Web
14
Une implémentation v2 /// Récupérer le singleton
public static function donneInstance() { self::msg("Recherche de l'instance...") ; // Une instance est-elle disponible ? if (!isset(self::$mypdo)) self::$mypdo = new myPDO() ; self::msg("Instance trouvée") ; // return self::$mypdo->pdo ; return self::$mypdo ; } 01:08:06 Programmation Web
15
Une implémentation v2 /// Surcharge de toutes les méthodes indisponibles de myPDO pour pouvoir appeler celles de PDO public function __call($methodName/** Nom de la méthode */, $methodArguments /** Tableau des paramètres */) { // La méthode appelée fait-elle partie de la classe PDO if (!method_exists($this->pdo, $methodName)) throw new Exception("PDO::$methodName n'existe pas") ; // Message de debogage self::msg("PDO::$methodName (".implode($methodArguments, ", ").")") ; // Appel de la méthode avec l'objet PDO $result = call_user_func_array( array($this->pdo, $methodName), $methodArguments) ; return $result ; } 01:08:06 Programmation Web
16
Une implémentation v2 /// Affichage de messages de contrôle
public static function msg($m /** Le message */) { if (self::$debug) Traceur::trace($m) ; } /// Mise en marche du debogage public static function debug_on() { self::$debug = true ; /// Arrêt du debogage public static function debug_off() { self::$debug = false ; 01:08:06 Programmation Web
17
Une implémentation v2 - Débogage
/// Singleton permettant de collecter des messages informatifs class Traceur { // Gestion de l'instance unique private static $_instance = null ; /// Objet Traceur // Atttributs de l'objet private $_messages = array() ; /// Tableau des messages private $_temps = null ; /// Instant de création /// Constructeur privé private function __construct() { $this->_temps = microtime(true) ; } /// Interdire le clonage private function __clone() { throw new Exception("Clonage de ".__CLASS__." interdit !") ; 01:08:06 Programmation Web
18
Une implémentation v2 - Débogage
/// Accesseur à l'instance qui sera créée si nécessaire private static function donneInstance() { if (is_null(self::$_instance)) { self::$_instance = new self() ; } return self::$_instance ; } /// Méthode statique de collecte de messages public static function trace($msg) { $instance = self::donneInstance() ; $instance->messages[] = $instance->duree() . " secondes : " .$msg ; 01:08:06 Programmation Web
19
Une implémentation v2 - Débogage
/// Calcul du temps écoulé depuis la création du traceur private function duree() { return number_format(microtime(true) - $this->_temps, 4) ; } /// Méthode statique d'affichage des messages collectés public static function affiche($avant = "<!--", $apres = "-->") { $messages = self::donneInstance()->messages ; $traces = null ; if (count($messages)) { $traces .= "{$avant}\n" ; foreach ($messages as $m) { $traces .= "{$m}\n" ; } $traces .= "{$apres}\n" ; } return $traces ; } } 01:08:06 Programmation Web
20
Une implémentation v2 - Débogage
/// Calcul du temps écoulé depuis la création du traceur private function duree() { return number_format(microtime(true) - $this->_temps, 4) ; } /// Méthode statique d'affichage des messages collectés public static function affiche($avant = "<!--", $apres = "-->") { $messages = self::donneInstance()->messages ; $traces = null ; if (count($messages)) { $traces .= "{$avant}\n" ; foreach ($messages as $m) { $traces .= "{$m}\n" ; } $traces .= "{$apres}\n" ; } return $traces ; } } 01:08:06 Programmation Web
21
Une implémentation v2 - Débogage
Utilisation de la classe Traceur dans la classe myPDO : affichage des traces à la destruction /// Destructeur de myPDO public function __destruct() { self::msg("Demande de destruction PDO...") ; // S'il y a une connexion établie... if (!is_null($this->pdo)) { // ... il faut se deconnecter self::msg("Demande de déconnexion...") ; $this->pdo = null ; self::$mypdo = null ; self::msg("Deconnexion effectuée") ; } self::msg("Destruction PDO terminée") ; echo Traceur::affiche() ; } 01:08:06 Programmation Web
22
Raffinement possible : Débogage (suite)
La solution est partielle : Les messages d'information concernent uniquement les méthodes de PDO Une requête préparée retourne un objet PDOStatement qui effectuera les méthodes bindValue, execute, fetch, … Comment tracer TOUTES les actions effectuées sur la base de données ? Implémenter un objet myPDOStatement 01:08:06 Programmation Web
23
Une implémentation V3 /// Encapsulation de PDOStatement
final class myPDOStatement { /// L'objet PDOStatement private $pdoStatement ; /// Constructeur public function __construct($_pdoStatement /** L'objet PDOStatement */) { myPDO::msg("Construction PDOStatement") ; $this->pdoStatement = $_pdoStatement ; } /// Destructeur public function __destruct() { myPDO::msg("Destruction PDOStatement") ; $this->pdoStatement = null ; 01:08:06 Programmation Web
24
Une implémentation V3 /// Surcharge de toutes les méthodes indisponibles de myPDOStatement pour pouvoir appeler celles de PDOStatement public function __call($methodName/** Nom de la méthode */, $methodArguments /** Tableau des paramètres */) { // La méthode appelée fait-elle partie de la classe PDOStatement if (!method_exists($this->pdoStatement, $methodName)) throw new Exception("PDOStatement::$methodName n'existe pas") ; // Message de debogage myPDO::msg("PDOStatement::".$methodName. " (".var_export($methodArguments, true).")") ; // Appel de la méthode avec l'objet PDOStatement return call_user_func_array( array($this->pdoStatement, $methodName), $methodArguments) ; } 01:08:06 Programmation Web
25
Une implémentation V3.1 Utilisation de myPDOStatement au lieu de PDOStatement ? public function __call($methodName/** Nom de la méthode */, $methodArguments /** Tableau des paramètres */) { // La méthode appelée fait-elle partie de la classe PDO if (!method_exists($this->pdo, $methodName)) throw new Exception("PDO::$methodName n'existe pas") ; // Message de debogage self::msg("PDO::$methodName (".implode($methodArguments, ", ").")") ; // Appel de la méthode avec l'objet PDO $result = call_user_func_array( array($this->pdo, $methodName), $methodArguments) ; return $result ; } // Selon le nom de la méthode switch ($methodName) { // Cas 'prepare' ou 'query' => fetchNamed case "prepare" : case "query" : $result->setFetchMode(PDO::FETCH_NAMED) ; // Retourne un objet myPDOStatement return new myPDOStatement($result) ; // Dans tous les autres cas default : // Retourne le résultat return $result ; } 01:08:06 Programmation Web
26
Aide au débogage, suite (et fin ?)
error_reporting(E_ALL) ; /** Mise en place d'une capture des exceptions non attrapées */ function exceptionHandler($exception /** L'Exception non attrapée */) { echo "<pre>\n" ; echo $exception->getMessage()."\n" ; echo "Trace d'execution :\n" ; echo $exception->getTraceAsString() ; echo "</pre>\n" ; } set_exception_handler('exceptionHandler') ; 01:08:06 Programmation Web
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.