Comment debugger un projet PHP?
par Olivier Serre

Introduction

A la différence de nombreux autres langages (e.g. JAVA, C, C++, OCaml…), PHP n'est pas compilé et est donc très avare de messages d'erreurs. L'objet de ce qui suit est de vous donner quelques pistes pour vous aider à debugger votre futur projet de Modex.

L'idée principale sera d'inclure dans votre code PHP des commandes permettant un debuggage de vos script PHP et des diverses interactions avec MySQL. Afin de ne pas afficher systématiquement les messages liés aux debuggage, on définira une variable Booléenne permettant d'activer ou non le mode debuggage.

Bien entendu, intégrer des fonctions de debuggage à votre code, ne vous dispensera pas de le structurer, de le commenter et de l'indenter correctement. Organiser le code permettra d'éviter beaucoup d'erreurs: mieux vaut prévenir que guérir!

Détails

Principe général, et fonctionalités attendues

Votre fichier PHP à débugger contiendra les lignes suivantes, qui définissent une variable Booléenne définissant le mode (true pour debugger, false pour ignorer les commandes de debuggages) et fera appel au fichier debug.php qui va contenir les diverses fonctions de debuggages.

<?
$Debug = true;
require("./debug.php");
?>

Nous allons maintenant décrire le fichier debug.php qui va contenir diverses fonctions de debuggage. A vous d'en ajouter d'autres selon vos besoins.

Commencez par prévoir dans votre fichier CSS une classe pour l'affichage des messages de debuggage. On pourra par exemple utiliser le style suivant (utilisé dans ce document pour afficher du code:

div.debug {
	background:lightgreen;
	border-style:dotted;
	border-color:blue;
	border-width:1px 1px 1px 1px;
}	

div.debug em {
	font-weight: bold;
	font-style: normal;
}

Un point important concerne l'accès à la valeur de $Debug dans les diverses fonctions de debug.php. Prenons l'exemple de la fonction suivante qui affiche un message si le mode debuggage est activé:

function debugPrintStatut(){
	global $Debug;
	if ($Debug){
		echo "<div class = 'debug'>Mode débuggage activé</div>";
	}
}

Vous remarquerez ici la commande global $Debug qui a pour effet que la variable $Debug, locale à la fonction debugPrintStatut fasse référence à la variable — globale — $Debug définie dans le fichier à débugger. Une alternative aurait été de passer $Debug comme paramètre de la fonction debugPrintStatut. Dans la suite nous donnons quelques fonctions de débuggage.

Afficher des variables

On peut souhaiter afficher la valeur d'une variable pour voir si celle-ci est est bien définie et possède la valeur attendue. On pourra utiliser la fonction qui suit. Cette dernière prend comme argument une chaîne de caractère qui donne le nom de la variable à afficher. Ainsi si l'on veut afficher le contenu de la variable $nomvariable on appellera la fonction debugPrintVariable("nomvariable"). Ce processus est inévitable si l'on souhaite tester l'existence ou le type de la variable à afficher. Afin de parler de la variable $nomvariable, on utilise le concept de variable dynamique: dans le code $$nomvariable fait donc référence à la variable dont le nom est $nomvariable. L'idée ici est d'avoir des noms de variables qui sont variables, c'est−à−dire un nom de variable qui est affectée et utilisée dynamiquement. Le reste du code donne un affichage selon les divers types de variables possibles.

function debugPrintVariable($nomvariable){
	global $Debug;
	global $$nomvariable;
	if ($Debug){
		if (isset($$nomvariable)){
			if(is_array($$nomvariable)){
				echo "<div class = 'debug'><em>Valeur du tableau $".$nomvariable.": </em>";
				if ($$nomvariable) {
					echo "<ul>"; 
					foreach ($$nomvariable as $cle => $valeur) { 
						echo "<li>$".$nomvariable."[$cle] = $valeur</li>"; 
					} 
					echo "</ul>";
				}
				echo "</div>"; 
			}
			else if(is_bool($$nomvariable)){
				echo "<div class = 'debug'><em>Valeur du Booléen $".$nomvariable.": </em>";
				if ($$nomvariable){ 
					echo "true";
				}
				else{
					echo "false";
				} 
				echo "</div>";
			}
			else if(is_string($$nomvariable)){
				echo "<div class = 'debug'><em>Valeur de la chaîne de caractères $".$nomvariable.": </em>".$$nomvariable."</div>";
			}
			else if(is_numeric($$nomvariable)){
				echo "<div class = 'debug'><em>Valeur de la variable numrique $".$nomvariable.": </em>".$$nomvariable."</div>";
			}
			else{
				echo "<div class = 'debug'><em>La variable $".$nomvariable." existe mais je ne suis pas sûr de l'afficher correctement. Sa valeur est </em>".$$nomvariable."</div>";
			}
		}
		else{
			echo "<div class = 'debug'><em>La variable $".$nomvariable." n'est pas définie!</em></div>";
		}	
	}
}

Afficher les variables des tableaux $_Get, $_Post et $_Session

Facile en utilisant la fonction précédente. Cela donne:
function debugPrintVariablePOST(){
	global $Debug;
	if ($Debug){
		debugPrintVariable("_POST");
	}
}

function debugPrintVariableGET(){
	global $Debug;
	if ($Debug){
		debugPrintVariable("_GET");
	}
}

function debugPrintVariableSESSION(){
	global $Debug;
	if ($Debug){
		debugPrintVariable("_SESSION");
	}
}

Interractions avec MySQL

Certaines erreurs viennent de l'appel à des requêtes MySQL: requêtes syntaxiquement incorrectes ou ne donnant pas de résultat. Pour cela on pourra afficher systématiquement la requête avant de l'effectuer (à l'aide de la fonction debugPrintVariable précédente en ayant préalablement stocké la requête à effectuer dans une variable), puis afficher la dernière erreur retournée par MySQL ou le nombre de réponses. Lorsque l'on effectuera diverses opérations en interaction avec MySQL on prendra garde à rattraper les erreurs. Par exemple:
mysql_connect("localhost", "root", "") or die("Erreur de connexion à MySQL"); 
mysql_select_db("Modex") or die("Erreur de connexion à la base de données"); 
$query = "SELECT * FROM News";
debugPrintVariable("query");
$reponse = mysql_query($query);
if (!$reponse) echo "Erreur SQL ".mysql_error()." sur ".$query; 

On pourrait évidemment factoriser tout ceci en une fonction qui prend en argument un chaîne de caractère codant une requête MySQL et l'exécute tout en donnant des informations supplémentaires si on est en mode débuggage.

function debugRequeteSQL($Requete){
	global $Debug;
	if ($Debug){			
		$reponse = mysql_query($Requete);
		if ($reponse){
			echo "<div class = 'debug'><em>La requête $Requete a été effectuée avec succcès </em></div>";
			return $reponse;
		}
		else{
			echo "<div class = 'debug'><em>La requête $Requete a provoqué l'erreur suivante: </em>".mysql_error()."</div>";
		} 
	}
}

Conclusion

En conclusion, n'oubliez pas d'organiser au mieux votre code, et n'hésitez pas à adapter les fonctions précédentes à vos besoin.