[php5] classe base de données

Soyez le premier à donner votre avis sur cette source.

Vue 16 538 fois - Téléchargée 792 fois

Description

Cette source se base sur la classe mysql de FhX :
http://www.phpcs.com/code.aspx?ID=33135
Elle y ajoute quelques subtilités ;-)
- permet de se connecter à n'importe quel sgbd dont on a définit la classe (2 à l'heure actuelle, à titre d'exemple : mysql et mssql), avec 1 seul et même appel. En fait, on instancie notre objet en lui passant en paramètre le nom de base. Cela permet de réutiliser le projet quel que soit le sgbd installée, et ce à moindre coût.
- n'autorise qu'une seule et unique instance de l'objet db.
- utilisation de la fonction magique __autoload

Source / Exemple :


//fichier dbfactory.cls.php

<?php
abstract class dbfactory {

    private static $instance;                   // Instance courante de la classe
    
    protected $_config;                         // Paramètres de configuration base de donnée.
    protected $query;                           // Ressource de query
    
    public $history = array();                  // Historique des requêtes
    public $query_id = 0;                       // Compteur de requêtes.

    // Initialise les variables de connections et active la connection à la base de donnée.
    // Constructeur protégé permettant de n'avoir qu'une unique instance de la classe grâce à la méthode singleton
     protected function __construct ($host=NULL, $user=NULL, $passwd=NULL, $name=NULL) {
        if ( !is_array($this->default_cfg) ) {
         throw new Exception('Vous devez remplir les paramètres de la configuration par defaut de votre base de donnée');
        }

        foreach ($this->default_cfg as $key=>$val ) {
             $this->_config[$key] = (isset($$key) ) ? $$key : $val;
        }

        unset($this->default_cfg); // Enlève les paramètres par defaut pour éviter toute confusion possible.
        $this->connect();
    }
   
    // usinage : permet d'instancier la classe correcte en fonction de la db choisie
    public static function factory ($type, $host=NULL, $user=NULL, $passwd=NULL, $name=NULL) {
        if (class_exists ($type)) {
            $className = $type;
            return new $className ($host, $user, $passwd, $name);
        } else {
            throw new Exception ('Pas d\'implémentation disponible pour ' . $type);
        }
    }
    
    // n'autorise qu'une seule instance de la classe
    public static function singleton () {
        if (!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
        }
    return self::$instance;
    }

    // on avertit le développeur qu'il n'a pas le droit de cloner l'objet instancié
    public function __clone() {
       trigger_error('Le clônage n\'est pas autorisé.', E_USER_ERROR);
    }

    // méthodes abstraites
    abstract protected function connect();
    abstract public function __destruct();
    abstract public function query($sql, $desc=NULL);
    abstract public function fetch_assoc($query=NULL);
    /*
    abstract public function num_rows($query=NULL);
    abstract public function fetch_row($query=NULL);
    abstract public function fetch_array($query=NULL);
    abstract public function free();

  • /
} ?> //fichier mysql.cls.php <?php class mysql extends dbfactory { protected $default_cfg = array( 'host' => 'localhost', 'user' => 'root', 'passwd' => '', 'name' => 'test'); // connection à la base protected function connect () { $this->_config['link'] = @mysql_connect($this->_config['host'], $this->_config['user'], $this->_config['passwd']); if (!$this->_config['link'] ) { throw new Exception('Erreur lors de la connection vers : '.$this->_config['host'].'.'); } $this->_config['base'] = @mysql_select_db($this->_config['name'], $this->_config['link']); if (!$this->_config['base'] ) { throw new Exception('Erreur lors de l\'ouverture de la base de donnée : '.$this->_config['name'].'.'); unset($this->_config); } echo 'connection réussie avec '.__CLASS__; } // Fermeture de la base de données au moment de la destruction de la classe. public function __destruct() { mysql_close($this->_config['link']); } // création d'une requête et historisation public function query ($sql, $desc=NULL) { $start = microtime (true); $this->query = @mysql_query ($sql, $this->_config['link'] ); $query_time = microtime (true) - $start; if ($this->query) { $this->query_id++; $this->history[$this->query_id] = array('desc' => $desc, 'query' => $sql, 'time' => $query_time); return $this->query; } else { throw new Exception (mysql_error() ); return false; } } // récupère les résultats dans un tableau associatif public function fetch_assoc ($query=NULL) { if (isset($query)) { $this->query = $query; } return mysql_fetch_assoc ($this->query); } } ?> //fichier mssql.cls.php <?php class mssql extends dbfactory { protected $default_cfg = array( 'host' => 'localhost', 'user' => 'root', 'passwd' => '', 'name' => 'test'); // connection à la base protected function connect () { $this->_config['link'] = @mssql_connect($this->_config['host'], $this->_config['user'], $this->_config['passwd']); if (!$this->_config['link'] ) { throw new Exception('Erreur lors de la connection vers : '.$this->_config['host'].'.'); } $this->_config['base'] = @mssql_select_db($this->_config['name'], $this->_config['link']); if (!$this->_config['base'] ) { throw new Exception('Erreur lors de l\'ouverture de la base de donnée : '.$this->_config['name'].'.'); unset($this->_config); } echo 'connection réussie avec '.__CLASS__; } // Fermeture de la base de données au moment de la destruction de la classe. public function __destruct() { mssql_close($this->_config['link']); } public function query ($sql, $desc=NULL) { $start = microtime(true); $this->query = @mssql_query ($sql, $this->_config['link'] ); $query_time = microtime (true) - $start; if ($this->query) { $this->query_id++; $this->history[$this->query_id] = array ('desc' => $desc, 'query' => $sql, 'time' => $query_time); return $this->query; } else { throw new Exception (mssql_erget_last_message()); return false; } } public function fetch_assoc ($query=NULL) { if (isset ($query)) { $this->query = $query; } return mssql_fetch_assoc ($this->query); } } ?> //fichier index.php exemple <?php // on utilise la fonction magique __autoload pour charger automatiquement tous les fichiers de classe lorsqu'un appel est demandé. function __autoload($class_name) { require_once ($_SERVER['DOCUMENT_ROOT'].'/tests/classes/'.$class_name . '.cls.php'); } try { $db = dbfactory::factory ('mysql', 'localhost', 'root', '', 'test'); } catch (Exception $e) { die($e->getmessage()); } $requete = $db->query ('SELECT * FROM te', 'test de requête'); while ($res = $db->fetch_assoc ($requete)) { echo '<br />', $res['1'], '<br />'; } var_dump ($db->history); ?>

Conclusion :


J'ajouterai de vraies fonctionnalités plus tard peut-être.
En attendant, vous n'avez plus qu'à implémenter (un simple copier coller suffit pour la version mysql) celles développées par FhX dans sa classe.

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
1
Date d'inscription
lundi 7 février 2005
Statut
Membre
Dernière intervention
29 octobre 2007

Salut,

Je trouve ta classe vraiment pas mal du tout. Par contre ya un point sur lequel je bloque:
C'est au niveau de ta classe abstraite dbfactory. Tu as une méthode factory, et une autre singleton.
A quel moment la méthode singleton est-elle appelée? Est ce automatique?
Sinon pourquoi ne pas combiner les deux en une seule fonction (faire ce que fait factory() dans singleton()
et ensuite
instancier un objet en faisant dbfactory::singleton(...)

Pourrais tu s'il te plait m'éclairer sur ce point, ça me trouble un peu,
j'ai l'impression qu'y a un truc qui m'échappe...

Je te remercie d'avance.

A+
Messages postés
10839
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
25
Je comprends, mais selon moi, il est normal d'avoir une erreur fatale si la classe que l'on tente d'instancier n'existe pas.
Ceci dit, tu as raison pour l'exception levée dans ce cas.
Voilà la modif qui permet d'éviter le fatal error, et d'attraper l'exception :

function __autoload($class_name) {
if (file_exists ($_SERVER['DOCUMENT_ROOT'].'/cls/dbfactory/classes/'.$class_name . '.cls.php')) {
require_once ($_SERVER['DOCUMENT_ROOT'].'/cls/dbfactory/classes/'.$class_name . '.cls.php');
}
}

PS : j'ai mis MES chemins, hein... ;-)
Messages postés
8
Date d'inscription
lundi 7 juillet 2003
Statut
Membre
Dernière intervention
21 novembre 2006

Le try catch n'y change rien...
En fait autoload fait des require_once().

Donc si je suis l'aglo de ton singleton, si je fait : $db = dbfactory::factory ('bidulesql', 'localhost', 'root', '', 'test');
Arriver à la ligne 32, class_exist() tente de vérifier que la classe bidulesql n'existe pas.
Mais apparament PHP interprètre ça comme une instanciation à la classe bidulesql (comme $r = new bidulesql();), et donc avec la fonction autoload, il essaye de faire un require_once({...}bidulesql.cls.php'); et comme ce fichier n'existe pas on a affaire à une erreur.
Je te laisse tester tu comprendra :)
Messages postés
10839
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
25
Hello,

tente un try {} catch () {} dans l'autoload, en attendant que je comprenne ce que tu expliques et que je teste ;-)
Messages postés
8
Date d'inscription
lundi 7 juillet 2003
Statut
Membre
Dernière intervention
21 novembre 2006

Je suis en train de faire une classe d'abstraction mysql en me basant sur tes sources (pour le singleton) et celle de FhX (Pour toute les options ajoutées), et je vien de voir une "erreur", et je voulais savoir s'il y aurai une solution.
En effet à la ligne 32 tu vérifies si la class est implémentée pour la base de données que tu veux, et tu génères une exception si elle ne l'est pas.

Le problème c'est que lorsqu'on utilise un autoload (comme c'est le cas), si la classe n'est pas implémentée, php génère une erreure fatal lors de l'execution de class_exist(). Il dit : Fatal error: require_once() sur le fichier de class qui n'existe pas vu qu'elle n'est pas implémenté. On dirait que autoload tente quand même de la charger. Evidemment l'exception que tu veux générer dans ce cas là est inutile...
Afficher les 20 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.