[POO] [PHP5] Design Pattern Singleton pour connexion base de données

nightkid83
Invité n'ayant pas de compte PHPfrance

04 juil. 2008, 14:02

Bonjour tout le monde, voila je suis débutant dans la POO et je viens de créer une classe qui me permet de me connecter a une base de données en utilisant PDO, le prob est que j'ai voulu utilisé le motif de conception "Singleton" mais je ne sais pas trop si ce que j'ai fait est juste ou pas. J'aimerai avoir votre avis ainsi que vos suggestions afin d'améliorer ma Classe, merci d'avance.

voici la Classe en question
<?php
 
class DatabaseConnection
{
    private static $_instance = null;
 
    private $_host;
    private $_user;
    private $_password;
    private $_dbname;
    private $_handle;
 
    private function __construct($dbname = 'nightkid')
    {
        $this->_host     = 'localhost';
        $this->_user     = 'root';
        $this->_password = '';
        $this->_dbname   = $dbname;
        $this->_handle   = null;
        
        try {
            $this->_handle = new PDO("mysql:host=$this->_host;dbname=$this->_dbname", $this->_user, $this->_password);
            $this->_handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            echo 'Connection established and database "' . $this->_dbname . '" selected.';
        } catch (PDOException $e) {
            die('Connection failed or database cannot be selected : ' . $e->getMessage());
        }
    }
 
    public function __destruct()
    {
        var_dump($this->_db); // Vérification
        if (!is_null($this->_handle)) {
            $this->_handle = null;
            echo 'Connection closed.';
        }
        var_dump($this->_db); // Une dernière vérification pour voir si l'objet a été détruit
    }
 
    public static function getInstance()
    {
        if (is_null(self::$_instance)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
 
    public function handle()
    {
        return $this->_handle;
    }
}
Maintenant, par exemple, j'utilise cette Classe comme suit :
<?php
 
require_once 'DatabaseConnection.php';
 
class Albums
{
    private $_db;
    private $_sql;
    private $_statement;
 
    public function __construct()
    {
        $this->_db = DatabaseConnection::getInstance()->handle();
    }
 
    public function __destruct()
    {
        var_dump($this->_db); // Vérification
    }
 
    public function addAlbum($artist, $title)
    {
        try {
            $this->_sql = "INSERT INTO albums (artist, title) VALUES (:artist, :title)";
            $this->_statement = $this->_db->prepare($this->_sql);
            $this->_statement->bindParam(':artist', $artist);
            $this->_statement->bindParam(':title', $title);
            $this->_statement->execute();
            echo 'Album added.';
        } catch (PDOException $e) {
            die('Error->addAlbum() : ' . $e->getMessage());
        }
    }
 
    public function editAlbum($id, $artist, $title)
    {
        try {
            $this->_sql = "UPDATE albums SET artist = :artist, title = :title WHERE id = :id";
            $this->_statement = $this->_db->prepare($this->_sql);
            $this->_statement->bindParam(':id', $id);
            $this->_statement->bindParam(':artist', $artist);
            $this->_statement->bindParam(':title', $title);
            $this->_statement->execute();
            echo 'Album information updated.';
        } catch (PDOException $e) {
            die('Error->editAlbum() : ' . $e->getMessage());
        }
    }
 
    public function deleteAlbum($id)
    {
        try {
            $this->_sql = "DELETE FROM albums WHERE id = :id";
            $this->_statement = $this->_db->prepare($this->_sql);
            $this->_statement->bindParam(':id', $id);
            $this->_statement->execute();
            echo 'Album deleted.';
        } catch (PDOException $e) {
            die('Error->deleteAlbum() : ' . $e->getMessage());
        }
    }
 
    public function selectAlbum($id = null)
    {
        try {
            if ($id !== null && $id > 0) {
                $this->_sql = "SELECT id, artist, title FROM albums WHERE id = :id";
                $this->_statement = $this->_db->prepare($this->_sql);
                $this->_statement->bindParam(':id', $id);
            } else {
                $this->_sql = "SELECT id, artist, title FROM albums";
                $this->_statement = $this->_db->prepare($this->_sql);
            }
            $this->_statement->setFetchMode(PDO::FETCH_ASSOC);
            $this->_statement->execute();
            return $this->_statement->fetchAll();
        } catch (PDOException $e) {
            die('Error->selectAlbum() : ' . $e->getMessage());
        }
    }
}
PS: J'aimerai aussi savoir si l'utilisation de la méthode magique "__destruct" dans la Classe "DatabaseConnection" est utile dans ce cas là ou pas.

Eléphant du PHP | 185 Messages

04 juil. 2008, 14:29

Salut,

Quelques remarques en vrac :
1) Tu n'utilises pas l'agument de ton constructeur.
2) Ton code serait plus simple si tu faisais hériter ta classe directement de la classe PDO (tu pourrais supprimer la variable $_handle).

Le principe est là sinon.

@+

ViPHP
ViPHP | 4674 Messages

04 juil. 2008, 23:45

Hey :),

Tu as bien compris le principe du Singleton, et le code est bon. Je n'ai rien à ajouter quant à ce qu'a dit savageman.

Pour répondre à ta question sur le __destruct, il ne te sert à rien pour ce que tu fais dedans. Si tu n'utilises plus l'objet, il sera automatiquement détruit. Et de toute façon, avec PHP 5.3, on aura un garbage collector, alors là, la panacée ;-).

La méthode __destruct est lancée avant de détruit l'objet. Donc elle peut fermer des connexions, mais en général, PHP le gère, donc autant le laisser faire.
C'est utile si tu veux écrire des logs ou des choses du genre. Dans ton cas, il n'y a pas grand intérêt.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Petit nouveau ! | 8 Messages

20 août 2008, 20:03

J'ajouterai un petit plus en rapport avec le singleton qui est, rappelons-le, le plus simple des design patterns ;)

N'oublie pas d'ajouter l'anti cloning (petit non perso)
 public function __clone()
{
  throw new Exception('Je suis un singleton, ne me clonez pas !');
}
Julien BreuxDevelopper | DéveloppeurBlog

Now
• AFUP (Member)
• LMV (Internal developer & Project Manager)
• Prestashop (External developer)
• PHP6 (External conceptor)

Eléphanteau du PHP | 36 Messages

01 sept. 2008, 18:02

Un autre anti cloning sympa :
private function __clone()
{
}
Julien Pauli - Formateur pôle PHP ZendFramework chez Anaska
Contributeur au projet Zend Framework
Ma page de tutoriaux, mon blog

Petit nouveau ! | 8 Messages

01 sept. 2008, 18:08

Un autre anti cloning sympa :
private function __clone()
{
}
Je trouve en effet le tient beaucoup plus simple. :oops:
Julien BreuxDevelopper | DéveloppeurBlog

Now
• AFUP (Member)
• LMV (Internal developer & Project Manager)
• Prestashop (External developer)
• PHP6 (External conceptor)

Eléphanteau du PHP | 25 Messages

27 nov. 2008, 02:09

Un autre anti cloning sympa :
private function __clone()
{
}
Je trouve en effet le tient beaucoup plus simple. :oops:
Pourriez-vous me dire à quoi sert le mot-clé __clone
merci d'avance
Non c'est moi le plus fort
Je serais absent du 8 au 14 courant
Annuaire des forums des écoles / Créez vos cours et exposés en ligne