[POO] Singleton ou référence ?

Résolu
cs_zeguizmo Messages postés 138 Date d'inscription vendredi 1 août 2003 Statut Membre Dernière intervention 16 juillet 2009 - 6 mai 2008 à 18:05
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

8 réponses

malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
6 mai 2008 à 19:40
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...
3
malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
7 mai 2008 à 19:33
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.
3
cs_garfield90 Messages postés 388 Date d'inscription lundi 7 juillet 2003 Statut Webmaster Dernière intervention 10 février 2009
8 mai 2008 à 00:27
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"
3
cs_zeguizmo Messages postés 138 Date d'inscription vendredi 1 août 2003 Statut Membre Dernière intervention 16 juillet 2009
6 mai 2008 à 18:59
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
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_zeguizmo Messages postés 138 Date d'inscription vendredi 1 août 2003 Statut Membre Dernière intervention 16 juillet 2009
7 mai 2008 à 16:53
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
0
cs_zeguizmo Messages postés 138 Date d'inscription vendredi 1 août 2003 Statut Membre Dernière intervention 16 juillet 2009
8 mai 2008 à 00:11
Ok, je vais opter pour la méthode mixte que tu décris, je trouverai une solution pour le debug :)

Merci encore !

ZeGuizmo
0
malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
8 mai 2008 à 12:44
Ou ArrayObject, mais c'est un peu plus compliqué.
0
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
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
0
Rejoignez-nous