Précédent   Forum des professionnels en informatique > PHP > Langage > Débuter
Débuter Forum d'entraide pour débuter en PHP. Avant de poster -> Cours PHP, FAQ PHP, Outils PHP, etc.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 15/02/2011, 07h49   #1
Candidat au titre de Membre du Club
 
Inscription : juillet 2004
Messages : 26
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 26
Points : 13
Points : 13
Par défaut [Singleton] pb de compréhension

Bonjour,

J'ai créée une classe singleton, qui me semble avoir un problème: à chaque fois que je transmet le formulaire l'instance est remise à zéro.

Au lieu de récupérer une instance créée une fois pour toute, la classe singleton agit comme une classe qui ne l'est pas...
ci-dessous mon code:

Code :
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
35
36
37
38
39
40
41
42
43
44
45
46
47
 
<?php
 
	// nom de fichier : bug_sgl.php
 
 
	// recuperation valeur
 
	Sgl::Instance()->Load();
 
	echo "<html><head></head><body>";
	echo "<br>Valeur de retour:(".Sgl::Instance()->mValeur.")";
 
	echo "<form name=test action=bug_sgl.php  method='get'>";
	echo "<input type ='submit' value='envoi' name='toto' />";
	echo "<input type ='hidden' value='retour' name='lavaleur' />";
	echo "</form>";
	echo "</body></html>";
 
 
	class Sgl {
 
		static protected $mInstance;
		static public $mCompteur;
 
		public $mValeur;
 
		protected function __construct( ) {	}
		protected function __destruct( ) { echo"<br> bye bye";	}
 
		public function Instance() {
			self::$mCompteur++;
			if( is_null(self::$mInstance) ){
				self::$mInstance = new Sgl();
				echo "<br>Sgl:::Creation de l'instance n°(".self::$mCompteur.")";
			} else {
				echo "<br>Sgl::Récupération de l'instance n°(".self::$mCompteur.")";
			}
				return self::$mInstance;
		}
 
		public function Load() {
			$this->mValeur =   isset($_GET['lavaleur'])  ?  $_GET['lavaleur'] : null ;
		}
 
	}
?>

l'affichage en sortie donne :

Sgl:::Creation de l'instance n°(1)
Sgl::Récupération de l'instance n°(1)
Valeur de retourretour)

Citation:
Warning: Call to protected Sgl::__destruct() from context '' during shutdown ignored in Unknown on line 0
- le compteur initialisé dans la classe sert de marqueur, il n'est incrémenté qu'une fois. Le problème c'est qu'il ne devrait pas l'être à envoi de formulaire.


Mes questions :
- Comment faire pour avoir un comportement du singleton habituel (l'instance est créée une seule fois) ?
- Comment éviter l'appel au destructeur ?

Merci de vos réponses
Duguesclin est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/02/2011, 08h39   #2
Membre Expert
 
Homme
Inscription : janvier 2004
Messages : 1 238
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Secteur : Finance

Informations forums :
Inscription : janvier 2004
Messages : 1 238
Points : 1 421
Points : 1 421
Contrairement a un autre langage de programmation, les classes de PHP ne sont pas persistés en mémoire d'un appel d'une page a une autre.

Si c'était le cas, il serait difficile de savoir quand libérer la mémoire (si tu ferme brutalement ton navigateur, le site n'est pas au courant que la mémoire doit être libérée)

Ta classe singleton n'est un singleton qu'au sein d'une seule requete HTTP d'un utilisateur.
Si tu appelles plusieurs fois getInstance dans ton code php au sein d'une même requete HTTP alors tu récupèrera le même objet.

=> Si tu veux une donnée qui soit persistée de page en page pour UN utilisateur il faut que tu utilises soit un cookie, soit une session.

=> Si tu veux une donnée qui soit persistée de page en page pour TOUT les utilisateurs, il faut que tu utilise une base de donnée ou un fichier.


Concernant le destructeur, il doit être appelé a la fin de la requete HTTP pour libérer la mémoire, et l'appel sort en erreur car il n'est pas public.
Dans ton cas, laisse PHP gérer la mémoire, et sauf si tu en as réellement besoin, laisse tomber le destructeur.
__________________
PHP :
Regle n°1 : mysql_query(...), mysql_connect(...) et mysq_select_db(...) doivent EN DEBUG etre suivies de or die(mysql_error()); (mais jamais en production)
Regle n°2 : Mieux encore : mysql_query($requete) or die("$requete<br/>".mysql_error());
Regle n°3 : echo '<pre>';var_dump($var);echo '</pre>'; affiche le contenu et le type d'une variable.
Publiez vos textes de fantasy et de science-fiction sur http://www.cercledefaeries.com/concours/
Fladnag est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 15/02/2011, 09h04   #3
Candidat au titre de Membre du Club
 
Inscription : juillet 2004
Messages : 26
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 26
Points : 13
Points : 13
Merci pour ta réponse.

Si je stocke mon instance singleton dans une variable de session, Php va quand même faire un appel au destructeur à l'envoi du formulaire pour libérer la mémoire?

Est-il possible de désactiver cet appel juste pour cette instance, et de gérer moi-même la vie de mon instance?
Duguesclin est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/02/2011, 10h03   #4
Membre Expert
 
Homme
Inscription : janvier 2004
Messages : 1 238
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Secteur : Finance

Informations forums :
Inscription : janvier 2004
Messages : 1 238
Points : 1 421
Points : 1 421
Tu ne peux pas empêcher PHP de détruire ton instance (sauf peut être si tu utilises des trucs compliqués comme la mémoire partagée, mais a moins de savoir exactement ce que tu fait et d'avoir accès a la configuration de ton serveur, on oublie ^^)

En session tu ne peux pas stocker une instance, mais uniquement du texte.
=> Soit tu stockes directement la ou les données correspondant a ton singleton
=> Soit tu t'amuse a serialiser/deserialiser ton objet dans ta session

Personnellement, tant que ton singleton est simple, je te conseille d'utiliser la session a la place.
Et quand je dis "a la place", c'est pas "en plus".
Bref, supprimer ton singleton et utiliser la session a la place.

Ou alors, si tu veux utiliser les 2 (mais c'est inutile a mon avis), tu fait un "faux" singleton qui est mappé sur la session genre :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MonSingleton {
  static private $mpInstance = new MonSingleton(); // au passage, initialiser un singleton de cette manière est mieux que de le faire dans getInstance
 
  public getInstance() {
    return self::$mpInstance;
  }
 
  protected __construct() {
  }
 
  public get($pKey) {
    return $_SESSION[pKey];
  }
 
  public put($pKey, $pValue) {
    $_SESSION[$pKey]=$pValue;
  }
}
__________________
PHP :
Regle n°1 : mysql_query(...), mysql_connect(...) et mysq_select_db(...) doivent EN DEBUG etre suivies de or die(mysql_error()); (mais jamais en production)
Regle n°2 : Mieux encore : mysql_query($requete) or die("$requete<br/>".mysql_error());
Regle n°3 : echo '<pre>';var_dump($var);echo '</pre>'; affiche le contenu et le type d'une variable.
Publiez vos textes de fantasy et de science-fiction sur http://www.cercledefaeries.com/concours/
Fladnag est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/02/2011, 10h36   #5
Modérateur
 
Avatar de ThomasR
 
Homme Thomas Rambaud
Développeur Web
Inscription : décembre 2007
Messages : 2 139
Détails du profil
Informations personnelles :
Nom : Homme Thomas Rambaud
Âge : 25
Localisation : France

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Multimédia et Internet

Informations forums :
Inscription : décembre 2007
Messages : 2 139
Points : 2 884
Points : 2 884
Bonjour,

Contrairement à ce qui est dit plus haut tu peux stocker ton objet en session.

Penses-juste que si dans cette classe tu as des références vers d'autres objets elles seront perdues. Pour palier à çà il faut dans la méthode __sleep définir quelles membres tu gardent en session, et dans la méthode __wakeup revaloriser les membres.
__________________
Développeur Web, accessoirement geek (ou l'inverse)
http://thomasrambaud.com
ThomasR est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/02/2011, 10h52   #6
Membre Expert
 
Homme
Inscription : janvier 2004
Messages : 1 238
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Secteur : Finance

Informations forums :
Inscription : janvier 2004
Messages : 1 238
Points : 1 421
Points : 1 421
Citation:
Envoyé par ThomasR Voir le message
Contrairement à ce qui est dit plus haut tu peux stocker ton objet en session.
Oui, tu peux avec des méthodes magiques de PHP, mais en fait ca revient a stocker du texte (serialiser/deserialiser les attributs non objets) et a demander a PHP de "reconstruire" l'objet sur la nouvelle page.

Par contre, la notion de singleton telle qu'on l'entend normalement, c'est a dire un objet UNIQUE, ne survivra pas si on le met en session. L'adresse de l'objet sera différente même si pour le développeur il a l'impression de manipuler le même objet.
__________________
PHP :
Regle n°1 : mysql_query(...), mysql_connect(...) et mysq_select_db(...) doivent EN DEBUG etre suivies de or die(mysql_error()); (mais jamais en production)
Regle n°2 : Mieux encore : mysql_query($requete) or die("$requete<br/>".mysql_error());
Regle n°3 : echo '<pre>';var_dump($var);echo '</pre>'; affiche le contenu et le type d'une variable.
Publiez vos textes de fantasy et de science-fiction sur http://www.cercledefaeries.com/concours/
Fladnag est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 15/02/2011, 11h09   #7
Candidat au titre de Membre du Club
 
Inscription : juillet 2004
Messages : 26
Détails du profil
Informations forums :
Inscription : juillet 2004
Messages : 26
Points : 13
Points : 13
OK c'est déjà plus clair, merci pour vos réponses.
Duguesclin est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 10h49.


 
 
 
 
Partenaires

Hébergement Web