Discussion:
probleme de singleton en php
(trop ancien pour répondre)
ownowl
2007-04-05 07:41:04 UTC
Permalink
bonjour à tous

je souhaite faire un singleton en php (c'est à dire qu'il n'y ai qu'une
seule instance d'une classe dans l'environnement php)

Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.


class TypesTruc {

private static $instance;

private $types = array();

private function __construct() {
$this->types['0'] = 'truc1;
$this->types['1'] = 'truc2';
}

final public static function getInstance() {
if (!IsSet(self::$instance)) {
error_log('initialisation du singleton');
self::$instance = new TypesTruc ();
}
return self::$instance;
}

public function getTypes(){
return $this->types;
}
}


une idée ?
Olivier
Thierry
2007-04-05 09:27:33 UTC
Permalink
Post by ownowl
bonjour à tous
bonjour
Post by ownowl
je souhaite faire un singleton en php (c'est à dire qu'il n'y ai qu'une
seule instance d'une classe dans l'environnement php)
ok
Post by ownowl
Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.
tu veux dire à chaque appel de la page ?

essaie ton code modifié suivant:

<?php
class TypesTruc {
private static $instance;
private $types = array();

private function __construct() {
echo "contruction <br />";
$this->types['0'] = 'truc1;
$this->types['1'] = 'truc2';
}

final public static function getInstance() {
if (!IsSet(self::$instance)) {
error_log('initialisation du singleton');
self::$instance = new TypesTruc ();
}
return self::$instance;
}

public function getTypes(){
return $this->types;
}
}

print_r(TypesTruc::getInstance()->getTypes());
echo "<hr />";
print_r(TypesTruc::getInstance()->getTypes());

?>

tu devrais constater que le constructeur n'est appelé qu'une fois dans la
page.
mais à chaque appel de le page il va être rappelé.

thierry
ownowl
2007-04-05 13:06:58 UTC
Permalink
merci de ta réponse
Post by Thierry
tu devrais constater que le constructeur n'est appelé qu'une fois dans la
page.
ok
Post by Thierry
mais à chaque appel de le page il va être rappelé.
oui je suis d'accord, mais c'est bien ca que je veux éviter. Je cherche
que le constructeur soit appelé une seule fois, à la première
utilisation de TypesTruc::getInstance(), quelque soit le nombre de pages
appelées ensuite.
Je précise que je viens du monde java, et qu'en java le constructeur
d'un singleton n'est appelé un seule fois durant la durée de vie de la
machine virtuelle. Cela est-il possible en php (sans utiliser un système
de cache (et d'ailleur un cache, pour être efficace doit bien rester en
mémoire en les appel des différentes pages))?

Olivier
Olivier Miakinen
2007-04-05 13:26:02 UTC
Permalink
Post by ownowl
oui je suis d'accord, mais c'est bien ca que je veux éviter. Je cherche
que le constructeur soit appelé une seule fois, à la première
utilisation de TypesTruc::getInstance(), [quel que] soit le nombre de pages
appelées ensuite.
Voyons les implications d'un tel mécanisme. L'objet serait créé une
fois sur le serveur, et ne serait jamais détruit jusqu'au reboot de
celui-ci. Tous les utilisateurs de ton script utiliseraient donc le
même (forcément, puisque le serveur ne peut pas distinguer entre deux
requêtes HTTP pour savoir laquelle vient de la même « session d'un
navigateur », laquelle vient d'une autre session, laquelle vient d'un
autre ordinateur, etc.).

Par suite, les objets non réutilisés consommeraient de la place mémoire
jamais libérée (à moins d'arrêter et relancer le serveur), et tu ne
pourrais jamais modifier un script contenant un tel objet sans arrêter
le serveur, puisque des utilisateurs pourraient toujours avoir besoin
de l'ancienne version.

Pas top, à mon avis.
Post by ownowl
Je précise que je viens du monde java, et qu'en java le constructeur
d'un singleton n'est appelé un seule fois durant la durée de vie de la
machine virtuelle.
Ne me dis pas que la machine virtuelle se trouve sur le serveur, et
qu'une seule et unique machine virtuelle est utilisée par tous les
visiteurs d'un site : je ne te croirais pas.

Et même si tu parlais d'une machine virtuelle tournant sur l'ordinateur
du visiteur, est-ce qu'elle conserve les objets quand tu quittes une
page d'un site pour en ouvrir une autre ? Parce que c'est bien ça qui
se passe avec PHP. Voir <http://faqfclphp.free.fr/#rub2.3>.
Post by ownowl
Cela est-il possible en php (sans utiliser un système
de cache (et d'ailleur un cache, pour être efficace doit bien rester en
mémoire en les appel des différentes pages))?
Quelle mémoire ?
ownowl
2007-04-05 17:01:40 UTC
Permalink
Post by Olivier Miakinen
Voyons les implications d'un tel mécanisme. L'objet serait créé une
fois sur le serveur, et ne serait jamais détruit jusqu'au reboot de
celui-ci. Tous les utilisateurs de ton script utiliseraient donc le
même (forcément, puisque le serveur ne peut pas distinguer entre deux
requêtes HTTP pour savoir laquelle vient de la même « session d'un
navigateur », laquelle vient d'une autre session, laquelle vient d'un
autre ordinateur, etc.).
Par suite, les objets non réutilisés consommeraient de la place mémoire
jamais libérée (à moins d'arrêter et relancer le serveur), et tu ne
pourrais jamais modifier un script contenant un tel objet sans arrêter
le serveur, puisque des utilisateurs pourraient toujours avoir besoin
de l'ancienne version.
Pas top, à mon avis.
c'est pourtant le but de ce design pattern. La gestion d'un
service/objet commun à l'ensemble des requêtes utilisateur.
Post by Olivier Miakinen
Post by ownowl
Je précise que je viens du monde java, et qu'en java le constructeur
d'un singleton n'est appelé un seule fois durant la durée de vie de la
machine virtuelle.
Ne me dis pas que la machine virtuelle se trouve sur le serveur, et
qu'une seule et unique machine virtuelle est utilisée par tous les
visiteurs d'un site : je ne te croirais pas.
et pourtant, généralement c'est bien comme ca que ca se passe ! Les
serveur d'apllication java du type weblogic, websphere, tomcat,...,
fonctionnent au sein d'une seule machine virtuelle, (même s'il est
possible d'en avoir plusieurs) et toutes les requêtes utilisateurs
tourne dans cette VM.
Post by Olivier Miakinen
Et même si tu parlais d'une machine virtuelle tournant sur l'ordinateur
du visiteur, est-ce qu'elle conserve les objets quand tu quittes une
page d'un site pour en ouvrir une autre ? Parce que c'est bien ça qui
se passe avec PHP. Voir <http://faqfclphp.free.fr/#rub2.3>.
Post by ownowl
Cela est-il possible en php (sans utiliser un système
de cache (et d'ailleur un cache, pour être efficace doit bien rester en
mémoire en les appel des différentes pages))?
Quelle mémoire ?
j'ai vu, sans toutefois creuser, qu'il y avait des bibliotèques ou
framework php qui proposent une gestion de cache. L'intérêt d'un cache,
c'est justement de garder un mémoire (sur le serveur) des informations
souvent sollicitées. Un accès mémoire sera toujours beaucoup plus rapide
qu'un accès fichier ou base de données
Olivier Miakinen
2007-04-05 18:25:34 UTC
Permalink
Post by ownowl
Post by Olivier Miakinen
Ne me dis pas que la machine virtuelle se trouve sur le serveur, et
qu'une seule et unique machine virtuelle est utilisée par tous les
visiteurs d'un site : je ne te croirais pas.
et pourtant, généralement c'est bien comme ca que ca se passe ! Les
serveur d'apllication java du type weblogic, websphere, tomcat,...,
fonctionnent au sein d'une seule machine virtuelle, (même s'il est
possible d'en avoir plusieurs) et toutes les requêtes utilisateurs
tourne dans cette VM.
Ça me semble une problématique différente. Tu peux très bien avoir
un serveur applicatif écrit en PHP, mais dans ce cas il tournera
indépendamment du serveur web « standard », même si ce serveur web
peut très bien servir à lancer des scripts PHP qui communiqueront
avec le serveur applicatif.
Post by ownowl
Post by Olivier Miakinen
Quelle mémoire ?
j'ai vu, sans toutefois creuser, qu'il y avait des bibliotèques ou
framework php qui proposent une gestion de cache.
Il serait intéressant que tu creuses. Parce que à côté du temps passé à
transmettre la requête HTTP (quelques centaines de seconde si tout va
bien, plusieurs secondes en RTC), du temps passé à lancer l'interpréteur
PHP s'il n'est pas en module Apache, du temps passé à lire et exécuter
le script PHP, et du temps passé à renvoyer la réponse HTTP (incluant
une page HTML complète depuis le DOCTYPE jusqu'à la balise </html>), je
ne suis pas sûr que le temps gagné à lire une mémoire partagée plutôt
que de chercher une info en base de données soit si important que ça.

D'autant plus que si les données changent il faudra bien les écrire sur
le disque quand même pour ne pas tout perdre en cas d'arrêt inopiné du
serveur.
Post by ownowl
L'intérêt d'un cache,
c'est justement de garder un mémoire (sur le serveur) des informations
souvent sollicitées. Un accès mémoire sera toujours beaucoup plus rapide
qu'un accès fichier ou base de données
Il reste à savoir si l'accès au fichier n'est pas négligeable par
rapport au temps passé sur le réseau.
ownowl
2007-04-06 11:27:07 UTC
Permalink
Post by Olivier Miakinen
Post by ownowl
L'intérêt d'un cache,
c'est justement de garder un mémoire (sur le serveur) des informations
souvent sollicitées. Un accès mémoire sera toujours beaucoup plus rapide
qu'un accès fichier ou base de données
Il reste à savoir si l'accès au fichier n'est pas négligeable par
rapport au temps passé sur le réseau.
C'est une application intranet, pas de soucis de réseau. La majorité des
requêtes passent par ajax, les données ne sont pas conséquentes en soit
mais peuvent être constituées d'un assemblage de pas mal de petit
fichier script; d'ou un éventuel goulot lors de l'accès à ces fichiers

Olivier
Bruno Desthuilliers
2007-04-05 20:09:32 UTC
Permalink
ownowl a écrit :
(snip)
Post by ownowl
c'est pourtant le but de ce design pattern. La gestion d'un
service/objet commun à l'ensemble des requêtes utilisateur.
La solution est simple: un autre process serveur fourni le service.
ownowl
2007-04-06 11:27:07 UTC
Permalink
Post by Bruno Desthuilliers
(snip)
Post by ownowl
c'est pourtant le but de ce design pattern. La gestion d'un
service/objet commun à l'ensemble des requêtes utilisateur.
La solution est simple: un autre process serveur fourni le service.
effectivement, mais ca nessécite de mettre en place un protocole de
communication (soap ou autre), n'est ce pas ?

Olivier
Bruno Desthuilliers
2007-04-10 14:04:56 UTC
Permalink
Post by ownowl
Post by Bruno Desthuilliers
(snip)
Post by ownowl
c'est pourtant le but de ce design pattern. La gestion d'un
service/objet commun à l'ensemble des requêtes utilisateur.
La solution est simple: un autre process serveur fourni le service.
effectivement, mais ca nessécite de mettre en place un protocole de
communication (soap ou autre), n'est ce pas ?
Ca me semble assez difficilement contournable, en effet.

slambert
2007-04-05 17:01:41 UTC
Permalink
Post by ownowl
oui je suis d'accord, mais c'est bien ca que je veux éviter. Je cherche
que le constructeur soit appelé une seule fois, à la première utilisation
de TypesTruc::getInstance(), quelque soit le nombre de pages appelées
ensuite.
Je précise que je viens du monde java, et qu'en java le constructeur d'un
singleton n'est appelé un seule fois durant la durée de vie de la machine
virtuelle. Cela est-il possible en php (sans utiliser un système de cache
(et d'ailleur un cache, pour être efficace doit bien rester en mémoire en
les appel des différentes pages))?
PHP n'est pas un serveur d'application.

Il n'y a pas d'espace mémoire commun à l'application.

Tout appel de page lance un process mémoire distinct dans lequel s'execute
le script, espace mémoire qui est ensuite purgé.

Il ne vous sera pas possible d'initailiser une statique et de chercher à
jouer avec sa valeurs depuis des appels de page distincts.

@++

Stef
Bruno Desthuilliers
2007-04-05 20:09:32 UTC
Permalink
Post by ownowl
merci de ta réponse
Post by Thierry
tu devrais constater que le constructeur n'est appelé qu'une fois dans la
page.
ok
Post by Thierry
mais à chaque appel de le page il va être rappelé.
oui je suis d'accord, mais c'est bien ca que je veux éviter. Je cherche
que le constructeur soit appelé une seule fois, à la première
utilisation de TypesTruc::getInstance(), quelque soit le nombre de pages
appelées ensuite.
Je précise que je viens du monde java, et qu'en java le constructeur
d'un singleton n'est appelé un seule fois durant la durée de vie de la
machine virtuelle.
C'est la même chose en PHP. Sauf que la durée de vie de l'interpréteur
est équivalente à celle d'une requête (bon, ok, techniquement ce n'est
pas tout à fait vrai si tu déploie PHP comme module Apache, mais dans la
pratique ça revient au même).
Post by ownowl
Cela est-il possible en php (sans utiliser un système
de cache (et d'ailleur un cache, pour être efficace doit bien rester en
mémoire en les appel des différentes pages))?
La solution habituelle est de cacher les objets "coûteux" à construire
et fréquemment utilisés dans une session. Mais - outre que c'est quand
même un poil différent puisque qu'il y a quand même autant d'instances
que de sessions - cela peut poser d'autres problèmes.

Si tu veux vraiment avoir une seule et unique instance d'un service pour
l'intégralité des requêtes, écris un processus serveur distinct dont ton
appli PHP sera cliente.
Thomas Labourdette
2007-04-05 10:47:53 UTC
Permalink
Bonjour,
Post by ownowl
je souhaite faire un singleton en php (c'est à dire qu'il n'y ai qu'une
seule instance d'une classe dans l'environnement php)
Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.
Je viens de faire le test en PHP 5 et je n'ai pas ton problème.

@+
--
Côme LAIZOTRE (signature et citation aléatoires)
Qu'est-ce que les femmes ont tous les mois et qui dure 3 ou 4 jours ?
Le salaire de leur mari...
ownowl
2007-04-05 12:57:40 UTC
Permalink
Post by Thomas Labourdette
Bonjour,
Post by ownowl
je souhaite faire un singleton en php (c'est à dire qu'il n'y ai qu'une
seule instance d'une classe dans l'environnement php)
Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.
Je viens de faire le test en PHP 5 et je n'ai pas ton problème.
@+
merci de ta réponse

Tu veux dire que dans ton log, tu n'as qu'une seule ligne de
'initialisation du singleton' quelque soit le nombre de page appelée ?
Olivier
Olivier Miakinen
2007-04-05 13:06:58 UTC
Permalink
Post by ownowl
Post by Thomas Labourdette
Post by ownowl
Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.
Je viens de faire le test en PHP 5 et je n'ai pas ton problème.
Tu veux dire que dans ton log, tu n'as qu'une seule ligne de
'initialisation du singleton' quelque soit le nombre de page appelée ?
Ah non, ça ce n'est pas possible. Lorsque le script PHP s'arrête, toute
la mémoire allouée est libérée... ce d'autant plus lorsque PHP est lancé
sous forme de CGI plutôt que de module Apache, puisque alors c'est
carrément le process qui s'arrête.

Si tu veux de la persistance de données entre deux appels de scripts, tu
dois utiliser un fichier ou une base de données.
LEMAIRE Mathieu
2007-04-05 18:25:34 UTC
Permalink
Post by Olivier Miakinen
Post by ownowl
Post by Thomas Labourdette
Post by ownowl
Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.
Je viens de faire le test en PHP 5 et je n'ai pas ton problème.
Tu veux dire que dans ton log, tu n'as qu'une seule ligne de
'initialisation du singleton' quelque soit le nombre de page appelée ?
Ah non, ça ce n'est pas possible. Lorsque le script PHP s'arrête, toute
la mémoire allouée est libérée... ce d'autant plus lorsque PHP est lancé
sous forme de CGI plutôt que de module Apache, puisque alors c'est
carrément le process qui s'arrête.
Ben les sessions en PHP elles sont gérées comment alors ???
Les singletons liés à une session pourraient être stockés dans $_SESSION
non ?

par contre ces variables ne seront pas dispo à vie comme sur ton serveur
d'app..

tiens, j'ai trouvé ça :
http://linuxfr.org/forums/21/8544.html
Post by Olivier Miakinen
Si tu veux de la persistance de données entre deux appels de scripts, tu
dois utiliser un fichier ou une base de données.
++
--
{Maz}
Olivier Miakinen
2007-04-05 18:50:58 UTC
Permalink
Post by LEMAIRE Mathieu
Post by Olivier Miakinen
Ah non, ça ce n'est pas possible. Lorsque le script PHP s'arrête, toute
la mémoire allouée est libérée... ce d'autant plus lorsque PHP est lancé
sous forme de CGI plutôt que de module Apache, puisque alors c'est
carrément le process qui s'arrête.
Ben les sessions en PHP elles sont gérées comment alors ???
En général, $_SESSION contient un id de session qui est une clé dans une
base de données. Mais nwonowl ne veut pas entendre parler de base de
données.
Post by LEMAIRE Mathieu
Les singletons liés à une session pourraient être stockés dans $_SESSION
non ?
Oui, si ce n'est pas trop gros. Mais dans ce cas, au lieu d'aller les
chercher sur le disque, les informations sont transmises (en aller et
retour) sur le réseau. En RTC je ne suis pas sûr qu'on y gagne, bien au
contraire.
Bruno Desthuilliers
2007-04-05 20:09:32 UTC
Permalink
Post by LEMAIRE Mathieu
Post by Olivier Miakinen
Post by ownowl
Post by Thomas Labourdette
Post by ownowl
Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.
Je viens de faire le test en PHP 5 et je n'ai pas ton problème.
Tu veux dire que dans ton log, tu n'as qu'une seule ligne de
'initialisation du singleton' quelque soit le nombre de page appelée ?
Ah non, ça ce n'est pas possible. Lorsque le script PHP s'arrête, toute
la mémoire allouée est libérée... ce d'autant plus lorsque PHP est lancé
sous forme de CGI plutôt que de module Apache, puisque alors c'est
carrément le process qui s'arrête.
Ben les sessions en PHP elles sont gérées comment alors ???
Par défaut, sur des fichiers dans le répertoire /tmp. On peut aussi
gérer les sessions dans un SGBDR si on veut faire de la répartition de
charge entre plusieurs serveurs web.
Post by LEMAIRE Mathieu
Les singletons liés à une session pourraient être stockés dans $_SESSION
non ?
C'est une technique courante, mais qui peut poser des problèmes aussi
quand on en abuse.
ownowl
2007-04-06 13:50:18 UTC
Permalink
Post by LEMAIRE Mathieu
par contre ces variables ne seront pas dispo à vie comme sur ton serveur
d'app..
http://linuxfr.org/forums/21/8544.html
Post by Olivier Miakinen
Si tu veux de la persistance de données entre deux appels de scripts, tu
dois utiliser un fichier ou une base de données.
Effectivement la mémoire partagée via IPC peut être une solution pour
les singletons

éventuellement, une solution pour cacher des pages serait d'utiliser un
link mémoire sur un disque physique :

http://developpeur.journaldunet.com/tutoriel/php/040330-php-nexen-optimiser5.shtml

Olivier
Jibux
2007-04-05 18:25:34 UTC
Permalink
Post by Olivier Miakinen
Si tu veux de la persistance de données entre deux appels de scripts, tu
dois utiliser un fichier ou une base de données.
Ou encore les variables de session
Bruno Desthuilliers
2007-04-05 20:09:32 UTC
Permalink
Post by Jibux
Post by Olivier Miakinen
Si tu veux de la persistance de données entre deux appels de scripts, tu
dois utiliser un fichier ou une base de données.
Ou encore les variables de session
Et à ton avis, elles sont stockées comment, ces variables ?
ownowl
2007-04-06 11:27:07 UTC
Permalink
Post by Bruno Desthuilliers
Post by Jibux
Post by Olivier Miakinen
Si tu veux de la persistance de données entre deux appels de scripts, tu
dois utiliser un fichier ou une base de données.
Ou encore les variables de session
Et à ton avis, elles sont stockées comment, ces variables ?
ca ne serait pas sur le disque, par hasard ?
slambert
2007-04-06 13:50:18 UTC
Permalink
Post by ownowl
Post by Bruno Desthuilliers
Post by Jibux
Ou encore les variables de session
Et à ton avis, elles sont stockées comment, ces variables ?
ca ne serait pas sur le disque, par hasard ?
Si, dans des fichiers textes situés dans le repertoire temporaires : )))

C'est d'ailleurs l'occasion de bien rappeller de ne JAMAIS rendre accessible
en ligne ce repertoire temporaire, justement pour cette raison principale.
: )

Stef
Jibux
2007-04-06 17:26:59 UTC
Permalink
Post by Bruno Desthuilliers
Post by Jibux
Ou encore les variables de session
Et à ton avis, elles sont stockées comment, ces variables ?
Dans des fichiers (mais sous *nix tout est fichier) qui sont stockés à
l'endroit défini par session.save_path.
Donc, on pourrait très bien imaginer changer le chemin par défaut vers
un ram-disk par exemple.
Mais je reconnais qu'il s'agit là d'un cas très particulier.
Thomas Labourdette
2007-04-05 18:25:34 UTC
Permalink
Post by ownowl
Post by Thomas Labourdette
Post by ownowl
je souhaite faire un singleton en php (c'est à dire qu'il n'y ai qu'une
seule instance d'une classe dans l'environnement php)
Le problème est : A chaque fois que je fais appel à
TypesTruc::getInstance()->getTypes()
je repasse systématiquement dans le constructeur.
Je viens de faire le test en PHP 5 et je n'ai pas ton problème.
Tu veux dire que dans ton log, tu n'as qu'une seule ligne de
'initialisation du singleton' quelque soit le nombre de page appelée ?
Non. Lors de plusieurs appels dans la même page. Pour le problème de
persistance d'un objet entre différents appels, les réponses ont été
données par ailleurs.

Il n'y a pas (à ma connaissance) de serveur d'application php comme tu peux
en connaître dans le monde Java.

@+
--
Djémal ALATAITE (signature et citation aléatoires)
Qu'est-ce qui fait 13,2 cm mais qui excite les femmes ?
Un billet de 500 Euros.
ownowl
2007-04-06 11:27:07 UTC
Permalink
Post by Thomas Labourdette
Non. Lors de plusieurs appels dans la même page. Pour le problème de
persistance d'un objet entre différents appels, les réponses ont été
données par ailleurs.
Il n'y a pas (à ma connaissance) de serveur d'application php comme tu peux
en connaître dans le monde Java.
@+
Ok, je fais maintenant bien le distinguo entre un serveur d'application
et l'environnement d'exécution de php
Olivier
Continuer la lecture sur narkive:
Loading...