[POO] Singleton ou référence ? [Résolu]

Messages postés
138
Date d'inscription
vendredi 1 août 2003
Statut
Membre
Dernière intervention
16 juillet 2009
- - Dernière réponse : cs_zeguizmo
Messages postés
138
Date d'inscription
vendredi 1 août 2003
Statut
Membre
Dernière intervention
16 juillet 2009
- 12 mai 2008 à 21:14
Salut à tous !

Je me pose actuellement une question, concernant les objets transversaux tels que l'objet gérant la base de données, classes de log etc ...

Comment passer ces objets aux autres objets de mon appli ? Par référence ou en utilisant le pattern design singleton ?

Par exemple, pour un objet user, faut-il créer une variable membre et passer par référence l'objet gérant la BDD lors de l'instanciation du user ? (accessible donc par $this->db a chaque fois que l'on veut envoyer une requête dans l'objet user).La classe de BDD serait donc instanciée une fois et passée par référence a chaque fois.

OU

Faut-il a chaque fois que l'on veut passer des requêtes dans une méthode la classe user commencer par instancier la classe gérant la BDD en utilisant un pattern design singleton ? (du type : $db = MySQL::singleton($params) ) La classe de BDD serait donc instanciée (singleton) dans chaque méthode de chaque objet qui a besoin de passer des requêtes.

Ou alors c'est strictement la même chose ? En terme d'écriture, personnellement je préférerai utiliser l'instanciation de singleton a chaque fois, c'est pour ça qu'existe ce type d'instanciation je pense. Par contre en terme de performance je ne sais pas ce que ca donne, si beaucoup de méthodes s'enchainent, je ne sais pas comment est gérée l'instanciation par singleton, si c'est aussi rapide d'accès qu'un travail sur la référence.

Peut etre encore je suis complètement dans le faux, et qu'il ne faut pas procéder de la sorte, j'écoute vos conseils avisés.

Merci beaucoup et bonne fin de journée

ZeGuizmo
Afficher la suite 

8 réponses

Meilleure réponse
Messages postés
10843
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
17
3
Merci
Hello,

rien ne t'empêche de mixer les deux :
dans le constructeur de la classe utilisatrices, tu récupères ton singleton et tu le stockes dans une propriété de ta classe.
Ainsi, ce sera toujours la même instance.
Et cela t'évitera de te planter si jamais tu passes explicitement une instance de ta classe DB à ta classe utilisatrice en tant que paramètre de son constructeur, en l'instanciant à plusieurs endroits dans ton code.
Ceci dit...:
class A {
    private $db;

    public function __construct(db $db) {
       $this->db = $db;
    }
}

class db {
    public static function getInstance(bla) {
       // bla bla
    }
}

$db = db::getInstance(bla);
$a = new A($db);

OU
class A {

    private $db;


    public function __construct() {

       $this->db = db::getInstance(bla);

    }

}

sont strictement identiques.
Pourquoi ? Parce que les objets passés en paramètres d'une méthode sont, en PHP5, TOUJOURS des références.
Dans le 1er cas, tu ne dupliques donc pas ton objet.
Dans le second non plus...mais le second est plus simple à mon sens.
Et que ce soit dans le 1er ou dans le second, dans tous les cas, tu utilises le même objet même dans plusieurs classes.

Ce que tu évoques comme risque ne se présente que dans un cas :

class db {
    public function __construct() {

    }
}

$a = new A(new db());
$b = new B(new db());
Là, tu auras deux copies de db, en effet. Mais si tu fais :
$db = new db();
$a = new A($db);
$b = new B($db);
tu n''auras qu'un seul objet.
Le risque est faible, en clair...

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 222 internautes nous ont dit merci ce mois-ci

Commenter la réponse de malalam
Messages postés
10843
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
17
3
Merci
Oui, la perte serait probablement significative si tu as bcp d'appels à ces méthodes. Tout est une question d'équilibre. Si tu n'appelles qu'une fois une méthode dans un script, et que seule cette méthode a besoin d'un objet précis, alors pourqui pas, par contre.

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 222 internautes nous ont dit merci ce mois-ci

Commenter la réponse de malalam
Messages postés
388
Date d'inscription
lundi 7 juillet 2003
Statut
Webmaster
Dernière intervention
10 février 2009
3
Merci
tu peux aussi regarder du coté de __toString(),

class user{
    private $nom;
    private $prenom
    private $db;

    function __toString(){
         return ''.$this->prenom."\n".$this->nom.'

'
    }
}

normalement, si tu fais
$oUser = new user('toto', 'titi');
print_r($oUser);
=> toto\ntiti

"They are 10 sorts of persons whose understand binary and whose not"

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 222 internautes nous ont dit merci ce mois-ci

Commenter la réponse de cs_garfield90
Messages postés
138
Date d'inscription
vendredi 1 août 2003
Statut
Membre
Dernière intervention
16 juillet 2009
0
Merci
Avec la fonction recherche j'ai raté ce post, qui figure quelques lignes en dessous du mien :

http://www.phpcs.com/infomsg_GESTION-USER_1115107.aspx#4

Ici neige d'hiver propose d'instancier par singleton puis de le passer dans une variable $user->db
Est-ce meilleur que de passer une reference vers l'objet de base de données au constructeur du user ?

J'imagine que c'est meilleur que d'instancier par singleton a chaque méthode, mais je n'en suis pas certain.

Car il y a un problème pratique, je trouve, a créer une variable membre 'db' pour chaque objet qui necessite une connection, c'est le debug. Quand on fait un joli print_r de notre objet user pour voir un peu quelle connerie on a pu faire pour qu'il s'appelle alfred au lieu de marcel, et qu'on utilise des objets debase de données un poil conséquents (type MDB2 de pear) ben le print_r prend des dizaines de pages. Quand il y en a qu'un, ca va, mais quand on travaille sur une liste de quelques dizaines de user, imagnez un peu les dégats.

Donc je reformule ma question, après tout ça :

En terme d'éthique et de performance, puis-je sérieusement instancier un objet qui peut être assez important (type gestion de base de données) par singleton à chaque méthode qui en a besoin, ou cela ne se fait pas et on préférera utiliser une variable membre de l'objet contenant la base de données.
Si la deuxieme solution est la bonne, est-il mieux de passer l'objet par référence au constructeur de classe, ou vaut-il mieux l'instancier dans le constructeur de classe en singleton ?

Merci, et désolé si je ne suis pas tres clair.

ZeGuizmo
Commenter la réponse de cs_zeguizmo
Messages postés
138
Date d'inscription
vendredi 1 août 2003
Statut
Membre
Dernière intervention
16 juillet 2009
0
Merci
Salut !

Merci de ta réponse très claire et détaillée, cela confirme ce que j'avais compris.

En revanche il me reste une interrogation.

Dans un objet, quand on déclare une variable membre assez lourde (genre db ..) et qu'on fait du print_r à la chaine pour debugger, cela devient très illisible. (quand on manipule une liste d'objets user par exemple, on se retrouve avec 10 fois l'objet db de printé, on ne retrouve plus rien à l'écran)

Je voudrais supprimer l'emploi d'une variable membre contenant la db (ou classe de log, ou classe de formulaire...) pour justement ne garder que les informations sémantiquement liées à l'objet.

Est ce que cela nuirait significativement aux performances et à la qualité du code si je déclare dans chaque méthode les objets dont j'ai besoin en singleton, au lieu d'utiliser une variable membre de l'objet que je manipule ?

Merci beaucoup et bonne fin d'après midi !
(et bon week end pour les chanceux qui font le pont)

ZeGuizmo
Commenter la réponse de cs_zeguizmo
Messages postés
138
Date d'inscription
vendredi 1 août 2003
Statut
Membre
Dernière intervention
16 juillet 2009
0
Merci
Ok, je vais opter pour la méthode mixte que tu décris, je trouverai une solution pour le debug :)

Merci encore !

ZeGuizmo
Commenter la réponse de cs_zeguizmo
Messages postés
10843
Date d'inscription
lundi 24 février 2003
Statut
Modérateur
Dernière intervention
2 mars 2010
17
0
Merci
Ou ArrayObject, mais c'est un peu plus compliqué.
Commenter la réponse de malalam
Messages postés
138
Date d'inscription
vendredi 1 août 2003
Statut
Membre
Dernière intervention
16 juillet 2009
0
Merci
Oh oui merci pour la méthode toString, je ne savais pas qu'elle existait pour tous les objets !

Ca fonctionne à merveille :)

Je n'ai pas encore regardé ArrayObject, ce n'est pas nécessaire car toString suffit, mais par contre je vais y jeter un coup d'oeil, autant mettre le plus d'outils possible dans ma besace.

ZeGuizmo
Commenter la réponse de cs_zeguizmo