[astuce] une variable globale dans une classe

Eléphant du PHP | 259 Messages

12 juil. 2008, 16:59

bonjour

je viens vous donner une petite astuce que j'ai bidouillé en faisant des expérimentations :

j'ai pour les pages de mon site plusieurs classes, une classe page qui sert à la génération de la présentation
des fonctions pour générer le contenu en fonction de la page appelée
une classe de connexion à la base de données

au début de chaque page, je créé une instance de la classe bdd pour avoir une connexion au serveur mysql
dans chaque instance des autres classes, je veux réutiliser cette même instance de base de données pour plusieurs raisons comme un compteur du nombre de requêtes envoyées ...

mais en php il n'est pas possible de faire
<?php

class page 
	{
	
	global $bdd; // instance de la classe bdd

       .....
        }

$bdd=new mysql();
$bdd->connexion('serveur','login','mdp');
$bdd->selection('bdd');


$page=new page();
...
?>
voici une petite astuce qui va nous permettre de contourner ce problème

pour ma classe page, je défini le constructeur
<?php
class page 
	{
	
	var $mysql;

	function __construct() // constructeur
		{
		global $bdd;
		$this->mysql=&$bdd;
		}
?>
de cette manière je pourrais réutiliser n'importe quelle variable globale, que ce soit une instance, un tableau ...

car je fais un passage d'adresse : je dis où se trouve cette variable globale à l'ensemble de l'instance de la classe

voila, n'hésitez pas à poser des questions

et si un mammouth passe ici, qu'il n'hésite pas à me corriger

++
l'hébergeur gratuit que j'utilisais: http://www.freeheberg.com (pas de limitte de débit, BP, 1à10Go, bdd mysql illimitées )
mainteant je suis chez OVH, payant mais plus adapté à de gros sites

Mammouth du PHP | 1511 Messages

12 juil. 2008, 17:49

Je me rappelle que c'était static pour avoir une persistance des données, enfin bon... :?

Mammouth du PHP | 965 Messages

16 juil. 2008, 10:09

Pour ma pars je gère sur un premier fichier toute la gestion de la connection a la base de donnée les erreurs a la connexion, mais aussi un mode de production et de pré-prodcution avec une variable protected de type $displayError en boolean, de cette facon un simple true / false a changer me donnera sur tout le site les erreurs complètes ou simplement un message "Une erreur est survenue", avec un lien de retour a la page précédente.

Pour la gestion des classes utilisant la classe de base de donnée je fais un peu comme toi mais de la manière suivante :
// Classe de gestion des programmes
class nomdeclasse {

	private $bdd;
	public $erreur;

	function __construct()
	{
		$this->bdd = new dbquery();
        }
ou dbquery est le nom de la classe pour la bdd.

ensuite c'est très simple j'utilise un simple
$this->bdd->req_query("REQUETE");
je ne vois pas pourquoi tu utilise une variable global, le protected me semble plus approprié.

Mammouth du PHP | 983 Messages

23 juil. 2008, 21:19

Les variables globales sont à éviter comme la peste dans un programme (effets de bords, visibilité de la variable, debogage difficile...).

Il existe de nombreuses façon de pallier à cela (singleton, variables statiques, passage d'instance d'objet en objet...).

A ta place, je ferais plutôt en sorte de faire de la classe dbquery un singleton.

Modérateur PHPfrance
Modérateur PHPfrance | 2572 Messages

23 juil. 2008, 22:34

La question est : ça sert à quoi une variable globale dans une classe, et surtout une ressource de connexion à une base de données. Car la globalité ne concerne que la portée du script chargé et exécuté dans un laps de temps très court suite à l'appel client. La globalité d'une variable PHP par la clause "global" ne s'étend malheureusement pas à toute l'application web durant toute la navigation. Pour cela on doit utiliser une sérialisation (session, fichier intermédiaire, bdd) mais on ne peut en aucun cas sérialiser une ressource de connexion bdd.

En tout cas, en ce qui concerne la réutilisation de connexion de bdd, PHP (comme la majorité des autres langages) n'ouvre pas de nouvelles connexions si une précédente est déjà ouverte sur le même serveur pour le même utilisateur et/ou script. Le cas de connexion persistante est aussi une solution pour la réutilisation de connexion même si la persistance peut engendrer quelques problèmes côté serveur.

Selon le concept objet, tout échange de données est une relation fonctionnelle entre l'objet et son environnement et doit être mis en place dans la conception du modèle de classes métier. La source des données à échanger est donc connue et doit être une autre classe.
La notion de statique de données au niveau classe veut dire simplement que toutes les instances de la classe se partagent les même données.

Par définition, toutes les propriétés (données) d'une classe, qu'elles soit privées, protégées ou publiques sont globales pour toutes les méthodes de la classe et de ses filles qui en héritent.
Mettre alors un "global" dans une méthode de classe rentre en conflit avec le concept de l'intégrité de la classe puisqu'il court-circuite le système d'accès aux données. D'autant plus que cette écriture (clause global dans une fonction) est spécifique à PHP hors modèle objet.
--------//////----//---//----//////
-------//---//----//---//----//---//
------//////----//////-----//////
-----||--------||--||---||
Prendre le recul n'est pas une perte de temps.


ps: Affrontez moi dans l'arène

ViPHP
ViPHP | 5886 Messages

23 juil. 2008, 23:38

Une solution pour avoir une connexion "globale" c'est à dire persistante de manière transparente, ce serait de stocker en session la classe gérant la base de données et implémenter les méthodes magiques __sleep() et __wakeup() pour détruire et recréer les connexions lors du stockage et de l'extraction de la session…

Mammouth du PHP | 19639 Messages

24 juil. 2008, 17:43

J'aurais deux remarques :
-1- ta classe est en PHP4 avec un passage par référence : le PHP4, c'est fini et en plus le passage par référence est automatique en PHP5 sans devoir jouer avec un "&"
-2- Et les constantes, ça sert à quoi à ton avis (et je ne parle pas des constantes de classe) ? Elles seront accessible même dans une classe il me semble, en tous cas je les utilise, je n'ai aucun soucis avec ça et je trouve ça plus propre qu'un "global"
:-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 67 Messages

25 juil. 2008, 09:29

J suis pas sur d'avoir bien compris ce qui était recherché mais c'est pas un cas ou se servir d'un singleton ça?

Mammouth du PHP | 19639 Messages

25 juil. 2008, 09:55

J suis pas sur d'avoir bien compris ce qui était recherché mais c'est pas un cas ou se servir d'un singleton ça?
Ce sont deux choses indépendantes. Le singleton te garantit de n'avoir jamais plus d'une instance à la fois d'une classe donnée.

Là, il est question de paramètres globaux pour une application. ça peut être nécessaire tant pour un singleton que pour des instances multiples. :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 67 Messages

25 juil. 2008, 10:46

Désolé pas les yeux en face des trous ce matin j me rend compte que ce que j voulait exprimé était pas tres claire et que je suis parti un peu HS (à partir du post de Sékiltoyai) en fait mais j'utilise une classe pour l'afichage de message (notament d'erreur) qui pourrai inspirer pour une connection BDD sauf que j'ai un peu dérivé du sujet et que j'ai pas envoyé la totalité de mon post. Donc toute mes excuses et un bon bout de code étant souvent plus parlant qu'un discourt de mec pas réveillé je post ma class :wink:

<?php
/**
 * Classe de messages d'information avec mise en session
 */

class message
{
	var $titre='';
	var $textes=array();
	var $classCSS;
	var $nomSession	= null;
	var $redirection=null;
	var $persistant=false;
	
	/**
	 * Constructeur
	 */
	private function __construct(){
	//function __construct(){
	}
	
	// DEBUT SINGLETON
	
	private static $MyInstance;
	
	public static function GetInstance(){
  		if (empty(self::$MyInstance)) {
    			self::$MyInstance = new message;
	    	}
	   	return self::$MyInstance;
 	}
	// FIN SINGLETON
	
	
	/**
	 * Défini la session utilisée
	 * @param string le nom du champs de session utilisé
	 * @access public
	 */
	function definirNomSession($nomSession){
		$this->nomSession=$nomSession;
		if(isset($_SESSION[$this->nomSession]))
		{
			$this->charger();
		}
	}
	
	/**
	 * Ajoute un message
	 * @param string message
	 * @access public
	 */
	function ajouter($message){
		$this->textes[]=$message;
		$this->enregistreSession();
	}
	
	/**
	 * Chane le titre du message
	 * @param string
	 * @access public
	 */
	function changerTitre($titre){
		$this->titre=$titre;
		$this->enregistreSession();
	}
	
	/**
	 * Chane la class CSS
	 * @param string
	 * @access public
	 */
	function changerCSS($nomClasse){
		$this->classCSS=$nomClasse;
		$this->enregistreSession();
	}
	
	/**
	 * Charge l'objet depuis la session
	 * @access private
	 */
	function charger() {
		if(isset($_SESSION[$this->nomSession])){
			$_SESSION[$this->nomSession]=array();
			$this->titre	= isset($_SESSION[$this->nomSession]['titre']) ? $_SESSION[$this->nomSession]['titre'] : '';
			$this->textes	= isset($_SESSION[$this->nomSession]['textes']) ? $_SESSION[$this->nomSession]['texted'] : array();
			$this->classCSS	= isset($_SESSION[$this->nomSession]['classCSS']) ? $_SESSION[$this->nomSession]['classCSS'] : '';
		}
	}
	
	/**
	 * Enregistre l'objet en session
	 * @access private
	 */
	function enregistreSession(){
		if($this->nomSession!==null){
			$_SESSION[$this->nomSession]=array();
			$_SESSION[$this->nomSession]['titre']	= $this->titre;
			$_SESSION[$this->nomSession]['textes']	= $this->textes;
			$_SESSION[$this->nomSession]['classCSS']= $this->classCSS;
		}	
	}
	
	/**
	 * Supprime l'objet de la session
	 * @access private
	 */
	 function viderSession(){
	 	if($this->nomSession!==null && $this->persistant==false){
			//unset($_SESSION[$this->nomSession]);
		}
	 }
	
	/**
	 * Ajoute une redirection javascript après l'affichage du message. N'affiche rien après le message
	 * @param mixed string ou array (string = url en dur, array = url via makeURL) url de la page vers laquel sera faite la redirection
	 */
	function ajouterRedirection($url){
		$this->redirection=$url;
	}
	
	/**
	 * Construit le code HTML du message
	 * @return string
	 * @access private
	 */
	function construireHTML() {
		$return ='';

		// Si vide
		if(count($this->textes)==0){
			return $return;
		}

		$return.='<div class="'.$this->classCSS.'">';
		
		// Titre
		if($this->titre!==''){
			$return.='<div class="message_titre">'.$this->titre.'</div>';
		}
		
		// Textes
		$return.='<div class="message_textes">'.implode('<br />', $this->textes).'</div>';
		$return.='</div>';
		
		return $return;
	}
	
}
?>

Modifié en dernier par vince_weed le 28 juil. 2008, 15:44, modifié 2 fois.

Mammouth du PHP | 19639 Messages

25 juil. 2008, 12:26

Je dirais quand même une chose qui me semble importante.

Afin de garder un maximum de portabilité dans les classes qu'on développe, il est de loin préférable de les rendre également indépendantes des paramètres des applications sur lesquelles on les utilise. Ce que je veux dire par là, c'est que si pour une application donnée on utilise une variable $xyz alors que pour une autre on utilise une variable $abc, le problème dans la classe est de savoir si on doit modifier la variable "globalisée" ou s'il ne serait pas opportun d'ajouter plutôt une méthode qui permettrait d'assigner la valeur à une constante de classe.

De cette manière, le nom de la variable est propre à l'application et la classe n'utilise que des noms de propriétés qui lui sont strictement dédiées indépendamment de l'application qui l'utilise.

En résumé, l'idée de départ utilisant global() est techniquement une mauvaise idée : ça rend le code peu portable.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 139 Messages

28 juil. 2008, 10:38

Je suis d'accord.
L'idée du singleton est bien meilleure !

Mammouth du PHP | 19639 Messages

28 juil. 2008, 12:23

Je suis d'accord.
L'idée du singleton est bien meilleure !
Encore une fois, peu importe qu'on utilise ou non un singleton. Il s'agit de variables globales utilisables dans une classe.

S'il s'agit d'une classe métier, c'est à dire propre à une application bien précise, classe étendant par exemple une classe plus générique et portable ssue d'un framework, l'idée proposée pourrait être valable, mais en aucun cas ce n'est vrai pour une classe qu'on doit pouvoir utiliser dans l'importe quel projet.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Petit nouveau ! | 1 Messages

15 juin 2011, 11:19

Je déterre ce topic étant tombé dessus de part mes recherche google. A priori l'astuce plus haute semble trouvé son intérêt en effet dans des conditions particulière, comme le dit cyrano.

Dans mon exemple j'utilise Zend framework et PhpBB3, j'ai donc du créer une class dans ma librairie pour que zend puisse communiquer et échanger des données avec phpbb3.

La classe ce construit comme suit :
    public function __construct()
    {
    	global $phpbb_root_path, $phpEx, $user, $db, $config, $cache, $template, $auth;
    	
		define('IN_PHPBB', true);
		$phpbb_root_path = 'forum/';
		$phpEx = substr(strrchr(__FILE__, '.'), 1);
		include($phpbb_root_path . 'common.' . $phpEx);
		$user->session_begin();
		foreach ($user as $key => $val)
		{
		$this->$key = $val;
		}
    }
A part l'améliorer de l'astuce de yuuzhantar je ne vois pas d'autres solutions.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8755 Messages

17 juin 2011, 17:39

A part l'améliorer de l'astuce de yuuzhantar je ne vois pas d'autres solutions.
hum une ou plusieurs méthodes permettant d'indiquer à la classe ces informations.

Comme la indiqué (rabâché ?) Cyrano, le modèle objet implique que l'objet est "autonome" dans le sens où il n'invente rien et utilise que les infos qu'il possède ou qu'on lui fournit.
or avec ta classe, si le code de phpbb est modifé plus rien ne fonctionne.
utilise plutôt un setter (unique pour plusieurs) et des variables de classe (ou simplement mettre les variables de classe en public mais bon je suis pas fan) pour avoir ces infos.

Au pire passe les dans le constructeur (ça peut se comprendre si les infos sont indispensables ;) ).


Bref global c'est le mal, même dans une simple fonction :mrgreen:

@+
Il en faut peu pour être heureux ......