phpInfo.netLes ArchivesLes éléPHPants

  
  Accueil
  Trucs & Astuces
  Scripts
  Regex
  Annuaire
  Articles

.
      
 Articles   Les variables dynamiques  Par Guillaume SMET   Avril 2001  

 »  Introduction
 »  Théorie
 »  Exemple 1 : Formulaire de modification
 »  Exemple 2 : fonctions dynamiques
 »  Conclusion générale


Introduction

Cet article a pour objectif de présenter un petit détail du PHP qui peut parfois avoir son utilité et permettre de résoudre de manière originale certains problèmes qui se posent régulièrement.

Les variables dynamiques sont en effet souvent très succintement traitées dans les différents ouvrages sur le PHP ("Elles sont dans la pratique bien peu utiles" [PHP Professionnel]). Il est bien entendu que cela ne va pas révolutionner votre manière de programmer mais ces variables dynamiques peuvent être bien utiles dans certains cas.

Théorie

Il n'y a que peu de choses à dire sur les variables dynamiques du point de vue de la théorie mais il est cependant intéressant de préciser certains points.

1. Nom des variables

Les variables dynamiques reposent sur un principe simple : le nom de la variable est lui-même une variable chaîne. Prenons de suite un exemple qui permettra d'éclaircir les choses :

<?php
    $gruyère
="44,50 F"; // On rentre le prix du gruyère au kilo
    
$beaufort="149,90 F"; // et le prix au kilo du beaufort (c'est cher le beaufort)

    // 1)
    
$fromage="gruyère"; // On choisit comme fromage le gruyère
    
echo $$fromage; // Affiche "44,50 F" soit le prix du gruyère

    // 2)
    
$fromage="beaufort"; // On choisit comme fromage le beaufort
    
echo $$fromage; // Affiche "149,90 F" soit le prix du beaufort
?>

Cet exemple ne vous aura certainement pas convaincu par son utilité (voir les chapitres suivants pour des exemples utiles) mais il aura au moins le mérite d'éclaircir le concept.

A l'étape 1), la variable $$fromage est en fait interprétée par PHP comme ceci : ${$fromage}. $fromage valant à cet instant "gruyère", notre variable $$fromage est alors équivalente à notre variable $gruyère.

Même si cet exemple n'est pas des plus pertinents, on peut déjà voir poindre un début d'utilité :

<?php
    $gruyère
="44,50 F";
    
$beaufort="149,90 F";
    
    
$liste=array("gruyère", "beaufort");

    foreach (
$liste AS $element)
        {
            echo
"Prix du ".$element." = ".$$element;
        }
?>

Cela reste un début d'utilité car on aurait tout aussi bien pu s'en sortir en utilisant un tableau du type $liste=array("gruyère"=>"44,50 F", "beaufort"=>"149,90 F") et faire un foreach($liste AS $fromage=>$prix).

Comme je le disais dans l'introduction, les variables dynamiques sont plus une manière originale de s'en sortir. Il y a en général toujours une autre solution (reposant souvent sur des tableaux d'ailleurs).

Quelques détails qui ont leur importance :

* Les variables dynamiques sont obligatoirement de la forme : $$nom_variable. On ne pourra pas avoir quelque chose du type :

<?php
    $nouvel_email
="quelquun@mail.com";
    
$element="email";

     
// On aura une parse error. Cela n'affichera pas $nouvel_email.
    
echo $nouvel_$element;
?>

* Lorsque que l'on manipule des tableaux, il est nécessaire de préciser certaines choses à l'interpréteur PHP. Prenons un exemple :

<?php
    $tableau1
=array("nom", "prenom", "email");
    
$tableau2=array("telephone", "portable", "adresse");

    
$tableau="tableau1";

    
// Cette ligne pose problème car l'interpréteur PHP ne sait pas si on parle
    // de $tableau1["1"] qui est bien défini ou de ${$tableau["1"]} qui lui
    // n'est pas défini.
    
echo $$tableau["1"];
?>

Il s'agit donc ici de préciser ${$tableau}["1"] ou de ${$tableau["1"]}.

2. Nom des fonctions

De même que le nom des variables, le nom des fonctions peut être dynamique.
L'exemple suivant est donc tout à fait licite (on supposera que les fonctions affiche_nom et affiche_prenom ont été définies auparavant) :

<?php
    $fonction
="affiche_nom";
    
$fonction($utilisateur); // Affiche le nom de l'utilisateur en cours

    
$fonction="affiche_prenom";
    
$fonction($utilisateur); // Affiche le prénom de l'utilisateur en cours
?>

Nous verrons un exemple plus précis et, je l'espère, plus utile dans le paragraphe 'Exemple 2 : fonctions dynamiques'.

Exemple 1 : Formulaire de modification

1. Contexte

Admettons que l'on dispose d'une base de données de type carnet d'adresses :
	nom | prenom | date_naissance | telephone | portable | email | adresse
C'est une configuration que l'on retrouvera dans nombre de bases de données.
Nous admettrons ici que la table contient déjà des entrées et que nous souhaitons modifier les informations déjà entrées.
Nous travaillerons sur deux fichiers : formulaire.php et form_res_formulaire.php qui sera notre résolution du formulaire.

2. Positionnement du problème

Faire un formulaire de modification ne pose pas vraiment de problèmes... Il suffit d'aller chercher les données dans la base de données et d'afficher les valeurs par défaut dans les champs avec l'attribut value de la balise input.
Nous nous centrerons ici sur le besoin de ne pas mettre à jour la base de données si les informations n'ont pas été modifiées et sur l'automatisation du "développement" de tels formulaires.
Nous simplifierons notamment le problème en utilisant le même type de balises pour toutes les informations de la base. Cela nous permettra de mieux mettre en valeur notre objectif premier.
Nous nous limiterons aux parties intéressantes du code.

3. formulaire.php

Ce fichier n'utilise pas les variables dynamiques mais il est nécessaire à la compréhension du formulaire form_res_formulaire.php.

<?php
/*
    En-tête XHTML
*/

/*
    Récupération des données dans la base de données -> tableau associatif
    $résultats contenant les données (utilisation de mysql_fetch_array)
*/

$liste = array("nom", "prenom", "date_naissance", "telephone", "portable",
               
"email", "adresse");

echo
"<form method=\"post\" action=\"form_res_formulaire.php\">\n";
echo
"   <table width=\"500\" cellspacing=\"0\" cellpadding=\"0\">\n";

foreach(
$liste AS $element)
{
    echo
"<tr>\n";
    echo
"<td width=\"200\">".$element."</td>\n";
    echo
"<td width=\"300\">\n";
    
    
// transmission du tableau $liste
    
echo "<input type=\"hidden\" name=\"liste[]\" value=\"".$element."\" />\n";
    
    
// transmission des anciennes valeurs sous la forme $ancien_email
    // par exemple
    
echo "<input type=\"hidden\" name=\"ancien_".$element."\" ";
    echo
"value=\"".$résultats[$element]."\" />\n";

    
// Champ de formulaire visible et modifiable
    
echo "<input type=\"text\" size=\"50\" name=\"".$element."\" ";
    echo
"value=\"".$résultats[$element]."\" />\n";
    echo
"</td>\n";
    echo
"</tr>\n";
}

echo
"</table>\n";
echo
"<input type=\"submit\" name=\"submit\" value=\"Valider\" />\n";
echo
"</form>";

?>

Ce fichier permet de générer un formulaire de modification à partir des éléments du tableau $liste. La transmission du tableau $liste et des anciennes valeurs des champs trouveront leur explication dans la résolution du formulaire.

4. form_res_formulaire.php

C'est ce fichier qui est réellement intéressant et c'est celui qui utilise les variables dynamiques. Comme précisé plus haut, seules les parties intéressantes du code seront visibles. Le but est ici de construire la clause SET de la requête SQL afin de ne mettre à jour la table que si nécessaire et de ne mettre à jour que les champs qui ont été modifiés dans formulaire.php.

<?php

// Le tableau $liste a été transmis pas formulaire.php
foreach($liste AS $element)
{
    
// Je rappelle qu'on ne peut utiliser $ancien_$element comme nous
    // l'avons vu au I.1.
    
$ancien_element="ancien_".$element;
    if($
$element != $$ancien_element)
    {
        
$tableau_clause_SET[]=$element."='".$$element."'";
    }
}

if(!empty(
$tableau_clause_SET))
{
    
/*
        Mise en forme de la requête et exécution
    */
}

?>

Déroulons à la main la première itération du foreach :

<?php
    $ancien_element
="ancien_"."nom";

    
// admettons que l'ancien nom soit "DUPONT" et le nouveau "DURAND"
    
if($nom != $ancien_nom)
    {
        
$tableau_clause_SET[]="nom"."='"."DURAND"."'";
    }
?>

En quelques lignes, nous avons construit la clause SET de notre formulaire et ce de manière totalement générique. Peu importe les valeurs entrées dans notre $liste de formulaire.php. Il ne reste plus qu'à mettre en forme la requête SQL à partir du $tableau_clause_SET.
Si $tableau_clause_SET est vide, on ne fait rien du tout car nous sommes dans le cas où aucune valeur n'a été modifiée dans le formulaire de modification.
Sinon, on ne met à jour que les valeurs qui ont été modifiées.

5. Conclusion

Nous avons parfaitement répondu au problème posé grâce aux variables dynamiques. Le code est en plus parfaitement réutilisable dans nombre de situations. Ce n'est certes pas la seule manière d'arriver au résultat demandé mais c'est finalement une manière élégante et parfaitement compréhensible.

NB totalement hors-sujet : je rappelle l'existence de l'attribut readonly de la balise input. Ainsi, on peut réutiliser le formulaire.php (en supprimant le superflu) pour afficher le contenu de la base. Avec une jolie feuille de style, c'est finalement assez réussi.
  HTML 4 : <input type="text" name="nom" value="DUPONT" readonly>
  XHTML 1.0 : <input type="text" name="nom" value="DUPONT" readonly="readonly" />


Exemple 2 : fonctions dynamiques

Cet exemple sera beaucoup plus court que le précédent. Il n'y aura aucune ligne de code mais juste une idée de départ.

1. Contexte

Admettons que nous souhaitions créer une page statistiques.php qui affiche des statistiques relatives à des utilisateurs d'un groupe (nombre de messages postés dans un forum, nombre de contacts dans un carnet d'adresses...).
Admettons que chacun de ces renseignements soit obtenu en faisant des requêtes du type COUNT(*) sur des bases différentes avec des conditions WHERE différentes.
Admettons maitenant que l'on souhaite pouvoir classer ces utilisateurs suivant les différents critères retenus précédemment mais tout en utilisant la même page pour l'affichage.
Ce contexte est très hypothétique mais il est juste utilisé pour donner une idée de situation où cela peut être utile.

2. Positionnement du problème

Nous passerons a priori le classement retenu dans l'URL comme suit : statistiques.php?id_groupe=4&ordre=forum.
Le problème est plus complexe qu'il n'y paraît car les informations sont dans des tables différentes et les clauses WHERE seront très différentes suivant les bases. On ne peut donc pas passer par un simple ORDER BY.
Il s'agit donc en fait de faire appel à des scripts différents suivant le classement souhaité.

3. Solution retenue

Il y a énormément de manières de résoudre ce problème. On peut notamment inclure un script différent suivant la valeur du paramètre de l'URL, ou faire appel à une fonction à laquelle on fait passer le paramètre $ordre et qui se reposera sur une structure conditionnelle.

Une solution élégante qu'on pourra retenir est la suivante :

<?php
    $fonction
="affiche_utilisateurs_suivant_".$ordre;
    
$fonction($id_groupe);
?>

Il faut bien sûr s'assurer que les paramètres transmis dans l'URL sont licites notamment pour ne pas faire appel à une fonction qui n'a pas été définie.

Conclusion générale

Les variables dynamiques sont effectivement un détail du PHP mais elles sont très faciles à utiliser et permettent parfois d'obtenir un résultat très intéressant à la fois par la possibilité de réutiliser le code facilement et par la lisibilité de celui-ci.
Elles peuvent donc parfois être fort utiles et fournir une solution agréable et facile à mettre en oeuvre à des problèmes concrets.
Synseo