begin process at 2012 05 30 18:38:28
  Trouver un code source :
 
dans
 
Accueil > Forum > 

PHP

 > 

POO

 > 

Classes & Objets

 > 

PDO + singleton


Derniers messages déposésPoser une question dans le forum ou lancer une discussion

PDO + singleton

dimanche 11 octobre 2009 à 22:49:39 | PDO + singleton

eltyty

Bonjour,

J'ai réalisé un code pour réaliser une connexion "singleton" avec PDO or j'ai une erreur.

Voilà le code du singleton :
Code PHP :
	class connexion_serveur {

           /**
	     * instance de la classe pdo
	     */
	    private $pdoinstance = null;

	    /**
	     * instance de la classe spdo
	     */
	    private static $instance = null;
 
	    private function __construct()	    {
	        try {
	        $this->pdoinstance = new pdo(db_dsn, db_user, db_password);
	        $this->pdoinstance->query("set names utf8");//for using utf-8
	        $this->pdoinstance->query("set character set 'utf8'");//for using utf-8
	        }
	        catch (pdoexception $e){
	            echo 'erreur : '.$e->getmessage().'<br>';
	            die();
	        }
	        
	    }
 
	    /**
	     * crée et retourne l'objet spdo
	     */
	    public static function getinstance()
	    {
	        if(is_null(self::$instance)or !isset(self::$instance))      {
	            self::$instance = new connexion_serveur();
	        }
	        return self::$instance;
	    }
        /**
        * empeche la copie externe de l'instance
        */
	    private function __clone() {
	        throw new exception('le clonage de spdo n\'est pas autoris&eacute;');
	    }
	}

Et maintenant j'essaie de faire une requête en PDO :
Code PHP :
$db=connexion_serveur::getinstance();
$insert = "insert into logs_erreurs (date_erreur, texte_erreur) values (?, ?)";
$statement = $db->prepare($insert);
$statement->bindparam(1, "test", pdo::param_str);
$statement->bindparam(2, "texte", pdo::param_str);
$statement->execute();

Et du coup j'obtiens : Call to undefined method Connexion_serveur::prepare()

Je début au niveau de PDO.

Merci de votre aide car après je compte mettre une class pour les requêtes qui utilisera cette connexion singleton.
dimanche 11 octobre 2009 à 23:13:20 | Re : PDO + singleton

neigedhiver

Salut,

Tu ne t'y prends pas correctement, pour instancier ton singleton.
Le constructeur est la fonction qui est TOUJOURS exécutée lorsque la classe est instanciée, c'est à dire immédiatement après sa création, de manière automatique.
Le singleton, en terme de motif de conception, est une version bien particulière de la factory. La factory (ou usine) est censée instancier un objet adapté à certains paramètres. Là, l'usine construit l'instance et la retourne si elle existe déjà.
L'instanciation doit donc se faire dans la méthode getInstance() :
Code PHP :
public static function getinstance() {
  null === self::$instance or self::$instance = new self();
  return self::$instance;
}

Plus parlant, le code suivant est synonyme :
Code PHP :
public static function getinstance() {
  if (null === self::$instance) {
    self::$instance = new self();
  }
  return self::$instance;
}


Les méthodes de PDO doivent être appelées sur l'objet instancié, pas en tant que méthodes statiques (ce qu'elles ne sont pas, et qui ne fonctionnera donc pas).
Plusieurs possibilités dans ton code. Soit tu stockes l'instance dans une variable, soit tu l'utilises directement. Depuis PHP5, les objets sont TOUJOURS passés par référence, ce ne sera donc pas une copie, mais l'objet lui-même qui sera alors stocké (donc s'il est modifié, il sera modifié partout ailleurs où il est utilisé). De plus, il n'était pas possible en PHP4 de chainer les appels de méthodes : si une méthode retournait un objet, il n'était pas possible d'appeler directement une méthode de cet objet, il fallait le stocker dans une variable intermédiaire puis appeler la méthode sur cette variable... Du coup, en PHP5, on peut faire ça :

Code PHP :
connexion_serveur::getinstance() -> query('select nom from table') -> fetchobj() -> nom;


Ou alors :

Code PHP :
$db = connexion_serveur::getinstance();
$db -> prepare('select login, password from users where login=:login limit 1');
$db -> bindvalue(':login', $_post['login'], pdo::param_str);
$db -> execute();


Hum... Je viens de voir que tu instancies déjà ta classe dans getInstance() ^^
Côté perfs, is_null() est moins rapide que de tester une égalité stricte avec NULL
Sinon, dans ton constructeur, tu NE DOIS PAS instancier un nouvel objet PDO. Il est préférable d'étendre la classe PDO :

Code PHP :
class connexion_serveur extends pdo {
  public function __construct() {
    parent::__construct($dsn, $username, $password);
  }
}


Euh bon, du coup, ma réponse est un peu désorganisée... :)

--
Neige

N'hésitez pas à lire la doc
dimanche 11 octobre 2009 à 23:22:52 | Re : PDO + singleton

neigedhiver

En fait, si, tu peux instancier un nouvel objet PDO dans ton constructeur et le stocker dans une propriété. Mais c'est inutile. Mais tu peux.
Si tu veux VRAIMENT faire ça, pour accéder aux propriétés et aux méthodes de l'objet PDO, il faut que ta classe fonctionne comme un proxy, grâce aux méthodes statiques __call(), __get() et __isset(), qui vont respectivement appeler une méthode de l'objet PDO, retourner une propriété, et vérifier si une propriété existe.
C'est pour cela que quand tu appelles une méthode de PDO sur ton objet Connexion_serveur ça ne fonctionne pas...

Mais vraiment, il est plus simple d'étendre la classe PDO, un proxy dans ce cas n'est absolument pas adapté ni en terme de conception ni en terme de performances.

Voilà :)

--
Neige

N'hésitez pas à lire la doc
lundi 12 octobre 2009 à 08:45:04 | Re : PDO + singleton

syndrael

Oups.. pas le temps de lire toute la réponse mais elle a le mérite de me rappelle la notion du OR qui peut être sympa. Merci de l'avoir fait remonter de mes souvenirs de 'mysql_query or die'
S.
lundi 12 octobre 2009 à 13:45:22 | Re : PDO + singleton

eltyty

Bonjour,
Et bien là je suis au taff mais je relis ça se soir et je te dis ça. En tout cas déjà merci pour ces explications.
lundi 12 octobre 2009 à 14:55:24 | Re : PDO + singleton

eltyty

Alors je prends un peux de temps là, au taff mais bon. Mais en relisant le tout c'est un peu confus.
En gros :
-la modification sur public static function getInstance() ok sans pb
-erreur quant au constructeur pas sûr d'avoir compris l'erreur et ce qu'il faut faire en fait.
Donc je dois faire une classe étendue du style :
Code PHP :
class connexion_serveur extends pdo {
  public function __construct() {
    parent::__construct($dsn, $username, $password);
 try {
	        $this->pdoinstance = new pdo(db_dsn, db_user, db_password);
	        $this->pdoinstance->query("set names utf8");//for using utf-8
	        $this->pdoinstance->query("set character set 'utf8'");//for using utf-8
	        }
	        catch (pdoexception $e){
	            echo 'erreur : '.$e->getmessage().'<br>';
	            die();
	        }
  }
}

Mais dans ce cas je laisse le constructeur de ma classe initiale vide ?
Du coup dans classe initiale j'obtiens :
Code PHP :
class pdo {

        	    /**
	     * instance de la classe pdo
	     */
	    private $pdoinstance = null;

	    /**
	     * instance de la classe spdo
	     */
	    private static $instance = null;

	    private function __construct()	    {
	
	 
	
	    }

	    /**
	     * crée et retourne l'objet spdo
	     */
	    public static function getinstance()
	    {
	        if(null === self::$instance or !isset(self::$instance))      {
	            self::$instance = new self();
	        }
	        return self::$instance;
	    }
        /**
        * empeche la copie externe de l'instance
        */
	    private function __clone() {
	        throw new exception('le clonage de spdo n\'est pas autoris&eacute;');
	    }
	}

Et après je peux utiliser classiquement mon prepare pour les insert, select, etc. comme suit :
Code PHP :
$db = connexion_serveur::getinstance();
$db -> prepare('select login, password from users where login=:login limit 1');
$db -> bindvalue(':login', $_post['login'], pdo::param_str);
$db -> execute();


je sais que ces questions doivent paraître bête mais...
Merci
lundi 12 octobre 2009 à 15:08:03 | Re : PDO + singleton

neigedhiver

Non, dans ton constructeur tu NE DOIS PAS instancier d'objet PDO, puisque l'objet qui est en cours de construction est justement un objet PDO !
Il faut cependant appeler le constructeur de la classe parente (PDO) :
parent::__construct($dsn, $username, $password);

Du coup, dans ton constructeur, au lieu de faire $this -> pdoinstance -> method(); tu fais : $this -> method()
Ton objet hérite bien entendu des méthodes de la classe PDO (c'est ce à quoi sert d'étendre une classe)

--
Neige

N'hésitez pas à lire la doc
lundi 12 octobre 2009 à 16:32:34 | Re : PDO + singleton

eltyty

K,

je look vite fais mon boss est pas là. Je test ce soir en espérant que j'ai tout compris. Je m'attendais à ce que tu modifis le code s'il n'était pas bon mais je regarde ça ce soir.
Merci déjà
mardi 13 octobre 2009 à 13:46:43 | Re : PDO + singleton

eltyty

Re,

alors j'ai tenté ceci mais il me manque qq chose :
Code PHP :
class pdo {
	public function __construct()	    {
			try {
	        $this->PDOInstance = new PDO(DB_SESSIONS_DSN, DB_SESSIONS_USER, DB_SESSIONS_PASSWORD);
	        $this->PDOInstance->query("SET NAMES utf8");//FOR USING UTF-8
	        $this->PDOInstance->query("SET CHARACTER SET 'utf8'");//FOR USING UTF-8
	        }
	        catch (PDOException $e){
	            echo 'Erreur : '.$e->getMessage().'<br>';
	            die();
	        }
	}

}
	class Connexion_serveur extends pdo{



	    /** Instance de la classe SPDO */
	    private static $instance = null;

	    private function __construct()	    {
			parent::__construct();
	    }

	    /** Crée et retourne l'objet SPDO   */
	    public static function getInstance()
	    {
	        if(null === self::$instance OR !ISSET(self::$instance))      {
	            self::$instance = new self();
	        }
	        return self::$instance;
	    }
        /**Empeche la copie externe de l'instance */
	    private function __clone() {
	        throw new Exception('Le clonage de SPDO n\'est pas autoris&eacute;');
	    }
	}

et j'appelle de cette manière :
Code PHP :
$db=Connexion_serveur::getInstance();
$insert = "INSERT INTO logs_erreurs (date_erreur, texte_erreur) VALUES (?, ?)";
$statement = $db->prepare($insert);

$statement->bindParam(1, "test", PDO::PARAM_STR);
$statement->bindParam(2, "texte", PDO::PARAM_STR);
$statement->execute();


Mais j'obtiens une erreur alors que je pensais avoir compris...
Help
mardi 13 octobre 2009 à 13:56:49 | Re : PDO + singleton

neigedhiver

Pourquoi est-ce que tu redéfinis la classe PDO ? PHP ne devrait pas aimer, parce qu'on ne peut pas définir une classe qui l'est déjà.
D'où l'extension de la classe PDO, ça, tu peux le faire.
Donc ce code :
Code PHP :
  try {$this->PDOInstance = new PDO(DB_SESSIONS_DSN, DB_SESSIONS_USER, DB_SESSIONS_PASSWORD);
  $this->PDOInstance->query("SET NAMES utf8");//FOR USING UTF-8
  $this->PDOInstance->query("SET CHARACTER SET 'utf8'");//FOR USING UTF-8
}
catch (PDOException $e){
  echo 'Erreur : '.$e->getMessage().'<br>';
  die();
}

tu dois le mettre dans le constructeur de ta classe. Et encore, sans le bloc try...catch, qui n'a rien à faire dans la classe : la classe génère une erreur si l'instanciation ne se déroule pas correctement (mauvais paramèrtes, connexion impossible, etc). La gestion des erreurs doit donc se faire à l'extérieur, ce n'est PAS le rôle de la classe de faire ça. A toi de déclarer, éventuellement, un gestionnaire d'exceptions personnalisées, ou de de mettre des blocs try...catch là où c'est nécessaire.

En gros, le constructeur de ta classe doit ressembler à ça :
Code PHP :
  public function __construct($dsn, $username, $password) {
    parent::__construct($dsn, $username, $password);
    $this -> query("SET NAMES utf8");
    $this -> query("SET CHARACTER SET 'utf8'");
  }


Et surtout, supprime la déclaration de ta classe PDO, elle existe déjà ;)
Etendre la classe PDO permet justement d'apporter à PDO des fonctionnalités qu'elle n'a pas et dont tu as besoin. Parmi ces fonctionnalités, on peut trouver l'automatisation de certaines tâches à l'instanciation, comme justement, la connexion en UTF8.

--
Neige

N'hésitez pas à lire la doc

1 2

Cette discussion est classée dans : code, connexion, instance, singleton, pdo


Répondre à ce message

Sujets en rapport avec ce message

Singleton encore [ par eltyty ] Bonjour, je ne comprends pas pourquoi j'ai une erreur. J'essaie d'utiliser le singleton mais je n'arrive pas à appeler une fonction à l'intérieur. Vo connexion Myslq PDO [ par vargas ] Bonjour à tous me voila avec une autre question présentement j'ai un fichier fonctions.php qui est une classe qui extend de PDO dans laquelle j'ai t connexion PDO [ par vargas ] Bonjour je voudrais créer une classe connexion à ma bd MySql et une autre classe qui vas contenir toutes mes requêtes. Pour le le moment j'ai ça : connexion sqlite en php5 [ par Karibot ] Bonjour, j'ai un problème lorsque je me connecte à une base sqlite avec sqlite_open. en fait, j'ai une erreur me disant que ma table n'existe pas mais procedure stockée avec parametre en sortie avec PDO/MySQL [ par poland_power ] Hello m'sieurs dames, en esperant que l'un de vous puisse m'aider, je vous expose mon soucis. j'ai une procédure stockée nommée avec un parametre de Formulaire d'ajout dans la base [ par sarrayosra ] salut, J'ai fais un formulaire d'ajout des employés dans la base de donnée et j'ai beaucoup de faute dans le code php, s'il vous plais quelqu'un m'ai Singleton : intérêt et bon fonctionnement ? [ par eltyty ] Bonjour, je suis en train de me mettre sur la notion de singleton afin d'obtenir une seul connexion mais du coup j'ai quelques questions. Actuellemen PDO serveur BDD distant [ par TheGorgo ] Bonjour, Je cherche à me connecter à un serveur de base de données distante en utilisant Doctrine. Lorsque je veux générer mon schèma de données, j'a connexion mysql impossible [ par nounours21_6 ] Bonjour tout le monde, Je dois développer un site en PHP et evidement je dois me connecter à une BDD! Ce n'est pas mon premier dev en PHP mais la j connexion à deux bases de données au meme temps via PDO [ par bouchenebfateh ] Bonjour à tous , je suis débutant en php OOP, je suis entrain de développer une application qui possède 2 bases de données, du coup je suis bloqué su


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

Photothèque

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,796 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales