IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PHP & Base de données Discussion :

singleton [PDO]


Sujet :

PHP & Base de données

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2007
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 112
    Par défaut singleton
    Bonjour à tous

    pour faire simple, j'essaie de faire un singleton sur un object PDO.

    Voici la classe de cette objet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    class instanceDB {
     
     	private static $instance = NULL;
    	private $db;
     
    	/**
    	 * Constructor
    	 */
    	function __construct(){
    		try {
    			$this->db = new PDO('mysql:host=host;dbname=db', 'login', 'pwd');
    		}
    		catch(PDOException $e) {
    			print "Erreur PDO ! : " . $e->getMessage() . "<br/>";
    			die();
    		}
    	}
     
    	public static function getInstance() {
    		if( !(self::$instance) ) {
    			self::$instance = new instanceDB();
    		}
    		return self::$instance;
    	}
     
    	function getDB(){
    		return $this->db;
    	}
    }
    Par contre après, quand je lance ce code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    require_once 'instanceDB.php';
    class table {
     
    	private $insert;
     
    	public function __construct() {
    		$instanceDB = instanceDB::getInstance();
    		var_dump($instanceDB->getDB());
    		$this->insert = $instanceDB->getDB()->prepare('INSERT INTO table (id) VALUES 0');
    	}
     
    	public function insert() {
    		$this->insert->execute();
    		return $this->insert->rowCount();
    	}
     
    }
    J'obtiens
    object(PDO)#2 (0) { }
    Fatal error: Call to a member function prepare() on a non-object in ..table.php
    Lorsque j'instancie une fois mon object PDO mais sans classe singleton, le var_dump() retourne la même chose et tout fonctionne!

    Des idées?
    Merci d'avance!

  2. #2
    Membre Expert Avatar de Madfrix
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    2 326
    Détails du profil
    Informations personnelles :
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 326
    Par défaut
    Bonjour, teste ceci :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    class instanceDB {
     
     	private static $instance = NULL;
     
    	public static function getInstance() {
    		if(self::$instance === null) {
    			try {
    				self::$instance = new PDO('mysql:host=host;dbname=db', 'login', 'pwd');
    			}
    			catch(PDOException $e) {
    				print "Erreur PDO ! : " . $e->getMessage() . "<br/>";
    				die();
    			}
    		}
    		return self::$instance;
    	}
    }
     
     
     class table {
     
    	private $insert;
     
    	public function __construct() {
    		$this->insert = instanceDB::getInstance()->prepare('INSERT INTO table (id) VALUES 0');
    	}
     
    	public function insert() {
    		$this->insert->execute();
    		return $this->insert->rowCount();
    	}
     
    }

  3. #3
    Membre confirmé
    Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2007
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 112
    Par défaut
    Ahhh YES

    Par contre t'aurais pas une ou deux précisions parce qu'en dehors du fait que le code est simplifié, je vois pas pourquoi mon code ne fonctionne pas !

    En tout cas merci

  4. #4
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    Salut

    Le problème c'est que tu dis "ça ne fonctionne", et du coup ça ne veut pas dire grand chose.
    Faut expliquer qu'est ce qui ne fonctionne pas, ou/et si tu as un message d'erreur, et bien le poster.

    D'ailleurs, n'as tu pas un message d'erreur ?

    Il y a un truc qui théoriquement n'est pas logique : private static $instance = NULL;
    Déclarer static sur une propriété c'est pour pouvoir l'exploiter en dehors de la classe (sans même l'instancier d'ailleurs).
    Cependant, la visibilité private c'est pour protéger une propriété (ou méthode) afin quelle soit exploitée que dans la classe, et non pas à l'extérieur, même dans une classe fille.

    Du coup, faire private static $une_proprite n'est pas correcte, et théoriquement tu devrais avoir une erreur lorsque tu appel instanceDB::getInstance()


    Théoriquement, $instance doit être static dans ton cas alors il vaut mieux le déclarer en public :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static $instance = NULL;

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    49
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 49
    Par défaut
    Bonjour à tous.

    RunCodePHP, c'est la staticité de $instance qui garantit son unicité, ce qui est le cœur même du singleton.

    D'autre part, un attribut (ou méthode) static non public n'a rien d'illogique.

    Tu pars du principe que static est fait pour utiliser un attribut ou une méthode "en dehors de la classe". C'est erroné. Quelque chose de statique dans une classe, c'est quelque chose qui ne varie pas d'une INSTANCE à l'autre de la classe.
    C'est donc quelque chose de COMMUN à la classe et à toutes ses instances. Si ce "quelque chose" est lié à des comportements encapsulés, il devra être privé.

    En l'occurrence, c'est exactement le cas ici, si $instance était public, comment garantir que getInstance() renvoie toujours la même instance d'objet ?

    D'ailleurs, toutes les mises en oeuvre du singleton présentées ici sont incorrectes.

    Aucune n'empêche d'avoir 2 instances du même objet. Vous utilisez ici le singleton pour rendre votre connexion BDD globale, c'est une grosse confusion.

    Si vous vouliez vraiment créer un singleton avec le PDO, voici la marche à suivre. Notez que le constructeur est privé aussi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class instanceDB extends PDO {
     
     	private static $instance = NULL;
     
    	/**
    	 * Constructor
    	 */
    	private function __construct($dsn, $username, $password, $driver_options = array()){
    		parent::__construct($dsn, $username, $password, $driver_options);
    	}
     
    	public static function getInstance() {
    		if (self::$instance === null) {
                        try {
    	                self::$instance = new self('mysql:host=host;dbname=db', 'login', 'pwd'));
    		    }
    		    catch(PDOException $e) {
    			print "Erreur PDO ! : " . $e->getMessage() . "<br/>";
    			die();
    		    }
    		}
     
    		return self::$instance;
    	}
    }
    Et encore, ça pose peut-être des soucis au niveau de la gestion des paramètres optionnels. Le problème de base est que le singleton n'a rien à voir avec tout ça.

    TekFanatiX, si tu veux accéder à ta connexion BDD "partout", tu la récupères simplement via une méthode statique dans une classe de fournitures ressources, c'est un "bootstrap" que tu essaies de faire, pas un singleton.

  6. #6
    Membre Expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Par défaut
    RunCodePHP, c'est la staticité de $instance qui garantit son unicité, ce qui est le cœur même du singleton.

    D'autre part, un attribut (ou méthode) static non public n'a rien d'illogique.
    Effectivement, tu as parfaitement raison.

    Je t'avoue que j'en était quasi convaincu.
    C'est quelque part rassurant de se voir raconter autant de conner* ... ça m'fera les pieds tiens

    Ceci dit, si j'avais pris soin 2 secondes pour regarder mon code (car j'utilise aussi PDO et en singleton), j'aurais remarqué que je l'avais mis en protected (et non pas public).
    Et bien du coup (j'ai bien fait de l'ouvrir finallement), j'en est profité de corriger ça, et bien sûr ça fonctionne parfaitement bien, aucune erreur comme je l'avais cru.
    Donc merci à toi d'avoir pris de le temps de corriger mes gros aprioris.


    Par contre, pour ce qui est de mettre le constructeur en privé, là, c'est le coup d'bâton :
    Fatal error: Access level to PdoMySQL::__construct() must be public (as in class PDO)
    A priori, on ne peu pas faire autrement que le conserver en public.


    D'ailleurs, toutes les mises en oeuvre du singleton présentées ici sont incorrectes.

    Aucune n'empêche d'avoir 2 instances du même objet. Vous utilisez ici le singleton pour rendre votre connexion BDD globale, c'est une grosse confusion.
    Il y avait un membre qui avait posté dans un topic une astuce pour verrouiller ça, pour empêcher la duplication de l'instance PDO, mais je ne parviens pas à remettre la main dessus.

    Par contre, comme j'ai adopté son astuce, alors je t'en fais part, et si tu as quelques minutes tu pourrais dire ce que tu en pense.

    (Je simplifie un peu, j'y mets juste l'essentiel, le principe)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    class PdoMySQL extends PDO {
        private static $instancePdo = null;
        private static $verrou = true;
     
        public function __construct() {
            if (self::$verrou) {
                throw new PDOException('[Singleton] Présence d\'une instance de la classe '.__CLASS__);
            }
            else {
                self::$instancePdo = parent::__construct('mysql:host='.SERVER.';dbname='.DATABASE, USERNAME, PASSWORD);
            }
        }
     
        public static function getInstance() {
            if (self::$instancePdo == null) {
                self::$verrou = false;
                self::$instancePdo = new PdoMySQL();
                self::$verrou = true;
            }
            return self::$instancePdo;
        }
     
        ... etc ...
    }
    Ceci me parais simple est efficace.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Servlet]Singleton & cache
    Par lucimast dans le forum Servlets/JSP
    Réponses: 4
    Dernier message: 15/12/2004, 16h36
  2. Singleton héritable ?
    Par rolkA dans le forum C++
    Réponses: 10
    Dernier message: 11/12/2004, 16h22
  3. [Débutant] pattern singleton
    Par SirDarken dans le forum Débuter avec Java
    Réponses: 22
    Dernier message: 11/12/2004, 01h55
  4. Mutiple row in singleton select ????? [Important, merci]
    Par SkyDev dans le forum Bases de données
    Réponses: 6
    Dernier message: 20/04/2004, 14h02
  5. [debutant]Singleton
    Par bafman dans le forum Langage SQL
    Réponses: 6
    Dernier message: 13/01/2004, 15h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo