Déboguer comme un chef en PHP avec XDebug

On retrouve encore trop souvent des développeurs PHP qui déboguent à l’ancienne avec des var_dump(), kint() ou dump().

Souvent, cela vient de la complexité à mettre en place XDebug et de la méconnaissance de son mode de fonctionnement.

Qu’est-ce qu’XDebug ?

XDebug est un outil de débogage pas à pas, qui permet de placer des points d’arrêt (breakpoints) et de suivre l’exécution en temps réel en consultant les variables ainsi qu’en pouvant évaluer et modifier leurs valeurs.

Maîtriser un tel outil fait gagner énormément de temps dans l’analyse d’un bogue.

Pourquoi choisir le débogage avec XDebug ?

Le débogage avec XDebug est certes plus complexe à mettre en place initialement car il demande de configurer votre environnement d’exécution (extension PHP XDebug + paramétrage) et votre IDE. Mais cette opération n’est à faire qu’une fois sur votre poste par projet. Ensuite, vous n’avez qu’à lancer la session de débogage sans rien avoir à configurer de plus.

Par rapport à du débogage à l’ancienne, c’est-à-dire avec des traces de log, vous gagnerez énormément de temps du fait de pouvoir visualiser et manipuler les variables (expression, définition de valeur), aussi bien dans le contexte du code où sont posés les points d’arrêt qu'en remontant la pile d’exécution.

Comment fonctionne XDebug ?

XDebug va se connecter à votre IDE. Il faut donc s’assurer que l’environnement d’exécution de votre application écrite en PHP ait accès à votre IDE.

Si comme beaucoup vous utilisez Docker, cela veut dire passer par l’interface docker0 de votre conteneur, qui est l'interface qui permet de faire le pont entre votre conteneur et le système d'exploitation principal de votre machine.

Pour trouver l'IP de l'interface docker0, taper la commande suivante :

  • macOS et Linux : ifconfig

    docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
            inet6 fe80::42:a3ff:febc:7ab4  prefixlen 64  scopeid 0x20<link>
            ether 02:42:a3:bc:7a:b4  txqueuelen 0  (Ethernet)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 13430  bytes 1949419 (1.9 MB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
  • Windows : ipconfig (chercher l'interface DockerNAT)

    DockerNAT on windows

Installation de XDebug

XDebug est disponible sous la forme d’une extension PHP. Bien souvent pour l’installer, il suffit d’installer le paquet de cette extension sur votre machine de développement ou dans votre conteneur.

Je vais donner la commande pour une Ubuntu 20.04 LTS, mais je vous invite à vous référer à la documentation de votre image Docker ou de votre distribution pour trouver les instructions d’installation :

apt install php-xdebug

Configuration de XDebug

C’est la partie la plus délicate, il est impératif de bien comprendre chacun des paramètres pour pouvoir ensuite identifier les éventuels problèmes de configuration qui pourront expliquer les dysfonctionnements potentiels.

Les paramètres importants pour déboguer en distant, c’est-à-dire d’un conteneur vers votre IDE sur l’hôte, sont les suivants :

  • xdebug.remote_enable => A valoriser à 1 pour activer.
  • xdebug.remote_host => Mettre l’IP de l’interface docker0 du conteneur ou host.docker.internal sous Docker for Mac ou Docker for Windows.
  • xdebug.remote_port => En général 9000, mais pourra être changé dans l’IDE.
  • xdebug.idekey (optionnel) => Un identifiant unique (utile si vous voulez exécuter plusieurs sessions de débogage en même temps sur des applications différentes).

Exemple de configuration :

/etc/php/7.4/fpm/conf.d/20-xdebug.ini
zend_extension=xdebug.so

xdebug.remote_enable=1
xdebug.remote_host="host.docker.internal"
xdebug.remote_port=9000

Activation dans votre IDE

Visual Studio Code

Sous VSCode, il vous faudra installer l’extension "PHP Debug" de Félix Fbecker puis créer un launch.json dans le répertoire .vscode avec le contenu suivant :

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen to XDebug",
            "type": "php",
            "request": "launch",
            "port": 9000,
            // server -> local
            "pathMappings": {
                "/var/www/docroot": "${workspaceRoot}/docroot"
            },
            "xdebugSettings": {
                "max_children": 128,
                "max_data": 512,
                "max_depth": 5
             }
        }
    ]
}

La clé pathMappings est utile si vous utilisez des conteneurs ou que votre application s’exécute sur un serveur distant, il permet d'indiquer la correspondance entre le chemin dans le conteneur, ou sur le serveur, et le chemin sur votre environnement local (hors conteneur).

Une fois cela fait, vous lancez le profile "Listen to XDebug" et vous pouvez commencer à déboguer.

PHPStorm

Vous devez vous assurer que le port d'écoute pour XDebug dans PHPStorm est configuré en accord avec votre configuration PHP (9000 par défaut) :

Puis ajouter une configuration de lancement :

Si vous utilisez un conteneur ou que votre application s’exécute sur un serveur, cochez l'option "Use path mappings" pour définir la correspondance entre le chemin dans le conteneur, ou sur le serveur, avec vos fichiers sur votre machine locale.

Ensuite il suffira de lancer le debug en mode écoute :

Si vous avez plusieurs applications qui tournent et que vous voulez déboguer l’une d’entre elles en particulier, vous pouvez utiliser la clé de session (idekey).

Dans ce cas, il faut désactiver l’écoute (avec l'icône en forme de téléphone), et appeler l’URL à déboguer avec le paramètre XDEBUG_SESSION_START valorisé avec la clé de session configuré dans votre IDE (ex : XDEBUG_SESSION_START=PHPSTORM).

Cela peut être simplifié en utilisant l’extension navigateur XDebug Helper :

Ligne de commande

Il est également possible de lancer le débogage pour une application PHP en ligne de commande.

Pour cela, il suffit de définir les paramètres XDebug via la variable d’environnement XDEBUG_CONFIG :

export XDEBUG_CONFIG="remote_enable=1 remote_host=<ip_docker0_ou_localhost> remote_port=9000 idekey=<vscode ou PHPSTORM>"

Si votre IDE est PHPStorm, il faudra en plus définir la variable PHP_IDE_CONFIG pour spécifier le nom de la configuration serveur ayant le path mapping correspondant à votre conteneur Docker ou à votre serveur :

export PHP_IDE_CONFIG="serverName=<nom_config_serveur>"

Ensuite, lancez votre script PHP CLI.

Fonctionnalités de débogage

Les points d’arrêt

L’élément principal dans un débogage pas à pas sont les points d’arrêt. Ils vous permettent d’indiquer à votre IDE à quel endroit vous souhaitez que l’exécution s’arrête pour inspecter le contexte de l’application à ce moment-là.

Il existe deux types de points d’arrêt :

  1. les points d'arrêt inconditionnels,
  2. les points d'arrêt conditionnels.

Comme vous l’avez certainement deviné, les points d’arrêts inconditionnels arrêteront l’exécution de l’application aux endroits où ils sont positionnés, quoiqu’il arrive, alors que les points d’arrêt conditionnels le feront que si les conditions définies sont remplies.

Ces derniers sont très pratiques pour déboguer des cas précis, en particulier sans avoir à passer ceux qui ne nous intéressent pas.

Pour placer un point d'arrêt, il suffit de cliquer devant une ligne sur la colonne à gauche de l'éditeur.

Pour définir une condition sur le point d'arrêt, il suffit de cliquer droit sur un point d'arrêt existant (ou clic-droit puis sélectionner Edit breakpoint sous VSCode).

L’inspecteur de variables

L’autre outil à disposition est l’inspecteur de variables. Vous aurez peut-être remarqué, dans la configuration de VSCode, nous avons mis des paramètres de profondeurs d’inspection (max_children, max_data, max_depth), ils permettent de définir la profondeur d'inspection des variables, comme, par exemple, dans des tableaux ou objets, directement depuis cet inspecteur. Nous n’avons pas eu à définir ces paramètres sous PHPStorm parce que dans son cas ils sont déjà assez importants par défaut.

Voyons à quoi ressemble cet inspecteur sous PHPStorm :

Et sous VSCode :

En plus d’inspecter les variables déclarées dans le contexte du point d’arrêt courant, il est possible de sélectionner une ligne de la pile d’exécution pour visualiser les variables des éléments appelants, ce qui est très pratique quand le bogue provient en réalité d’un élément plus en amont dans la pile d’exécution.

Sous PHPStorm, cet inspecteur de variables permet également de modifier dynamiquement la valeur d’une variable :

L’inspecteur d’expressions

Un autre outil très puissant dans le débogage pas à pas est l’inspecteur d’expressions.

Celui-ci vous permet de définir des expressions complexes, ce qui peut s'avérer très utile, par exemple pour cibler un élément particulier d’un tableau, ou visualiser la taille d’une chaîne de caractère ou d’un tableau, sans modifier le code :

Avancer dans le code

Si cela s'appelle un débogueur pas à pas, c'est parce qu'il permet, une fois arrêté à un endroit du code, d'ensuite le parcourir ligne par ligne ou jusqu'au prochain point d'arrêt.

Dans les captures d'écran ci-dessus, vous aurez peut-être remarqué les barres d'outils :

PHPStorm :

VSCode :

Elle servent à parcourir le code:

: Avancer jusqu’au prochain point d'arrêt

: Passer à la ligne suivante sans entrer dans la fonction

: Entrer dans la fonction

: Sortir de la fonction

: Reprendre l’exécution au début

: Interrompre la session de débogage

Les autres capacités de XDebug

En plus de proposer une fonctionnalité débogage pas à pas, XDebug est également capable de faire du profilage, afin de mesurer précisément les performances de votre code.

Le profilage mérite un article à lui seul, nous approfondirons ce sujet dans un autre billet.

Bertrand

Bertrand n’est pas avare d’échanges ni de partages. Très impliqué en tant que citoyen et informaticien, il croit en une société respectueuse des écosystèmes et de la planète : c’est peut-être pour cela qu’il aime l’hybride !

Et si vous ne le rencontrez pas pendant un de ces talks sur la Blockchain ou l’internet décentralisé vous pourrez discuter avec lui à la mi-temps d’un match de Hockey des Corsaires de Nantes.

Tentez aussi votre chance en vous rendant dans le cop de son équipe favorite, c’est celui qui tape le plus fort sur son tambour !

Retours aux publications