Visual Studio Code si integra perfettamente con Xdebug, permettendoci di svolgere il debug dei file PHP, sia sul nostro PC, sia in esecuzione su di un server remoto. Abbiamo così a disposizione lo stop sui breakpoint, l'esecuzione delle singole righe (step-by-step), l'ispezione delle variabili e tutto quello che serve per verificare i nostri applicativi, programmare meglio e più velocemente. In questa guida vedremo dunque come configurare Visual Studio Code con Xdebug per eseguire il debugging degli script PHP, locali e remoti
Procedura aggiornata e validata ad agosto 2024 per funzionare al meglio con le versioni moderne di Visual Studio Code su Windows e Linux
La seguente procedura funziona con tutte le piattaforme supportate da Visual Studio Code. Nello specifico, io l'ho svolta con Windows 11, Windows 10 e Linux (Ubuntu).
La trattazione è appunto incentrata su Visual Studio Code e Xdebug. Per raggiungere il medesimo risultato con phpStorm, si veda quest'altro approfondimento dedicato:
Debug di pagine PHP con Xdebug: come funziona
Prima di entrare nel vivo della trattazione, è importante capire come funziona il debug dei file PHP tramite Xdebug:
- Xdebug si integra con l'interprete PHP tramite un'estensione, da installare sullo stesso PC o server che esegue gli script PHP
- Xdebug si connette all'IDE (l'ambiente di sviluppo, come Visual Studio Code, phpStorm ecc.) tramite una porta configurabile - di default è la
TCP/9003
- Xdebug invia all'IDE le informazioni necessarie affinché esso possa visualizzare lo stato dell'applicazione
Il concetto-chiave da portare a casa è che la porta viene aperta dall'IDE. Questo ha una conseguenza diretta: è Xdebug che si connette a Visual Studio Code, e non viceversa!
Non è dunque necessario che il sistema sul quale è in esecuzione Visual Studio Code sia lo stesso sul quale gira lo script PHP. Di più: il computer con l'ambiente di sviluppo potrebbe non avere nemmeno installato PHP e Xdebug, e i due computer potrebbero persino utilizzare un sistema operativo diverso.
L'unico vero requisito è che il PC sul quale gira Visual Studio Code renda accessibile la porta a quello con PHP e Xdebug.
Capito questo, entriamo nel vivo dell'installazione di Xdebug.
Passo 1: Installare PHP e Xdebug
Per prima cosa, è necessario installare PHP e Xdebug su un PC o server. Lo ripeto ancora una volta per la massima chiarezza: non è necessario che il PC sul quale programmiamo con Visual Studio Code sia lo stesso che eroga le pagine PHP. È possibile che si tratti di PC differenti e, magari, dotati di sistemi operativi differenti. Xdebug va installato solo sul PC/server con PHP seguendo questa guida:
» Leggi: Xdebug con Ubuntu - Come installare e configurare PHP per il debugging locale o remoto
Passo 2 (solo per il debug remoto): SSH e RemoteForward
Se il PC sul quale programmi con Visual Studio Code è lo stesso che esegue l'interprete PHP, sei in una situazione di debug locale. Lo stesso dicasi se l'interprete PHP è in esecuzione all'interno di Docker, Vagrant, oppure all'interno di macchina virtuale, ma sempre sul PC locale. Ancora: parliamo di "debug locale" anche quando PHP è in esecuzione su un PC diverso da quello di Visual Studio Code, ma entrambi sono all'interno della stessa rete locale (LAN). In tal caso, possiamo saltare al Passo successivo.
Se però il PC con Visual Studio Code e quello che esegue PHP sono realmente "remoti", ovvero separati da Internet, siamo nello scenario di debug remoto. In tal caso, dobbiamo configurare, sul PC con Visual Studio Code, un tunnel SSH che permetta di esporre la porta di Visual Studio Code al sistema remoto: è quella alla quale Xdebug si connetterà per consentire la magia del debugging.
Allo scopo, dobbiamo creare un "profilo" di connessione SSH all'interno del nostro file .ssh/config
come dettagliato in quest'altro approfondimento:
Il risultato ultimo sarà simile a questo:
Host azienda
Hostname utenti.mia-azienda.com
User pippo
Nella trattazione originale indicavo di aggiungere la direttiva "RemoteForward 9003 localhost:9001" al proprio file .ssh/config. Oggi, questo non è più necessario e, anzi, genera un errore. Non farlo!
Di nuovo: fai riferimento alla guida dedicata a .ssh/config per le istruzioni passo passo alla creazione di questo "profilo".
Passo 3: Installare Visual Studio Code e PHP Debug
Se ancora non l'hai fatto, procedi a scaricare e installare l'IDE:
» Download: Visual Studio Code
Subito dopo, installa l'estensione per Visual Studio Code di nome PHP Debug. In caso l'installazione tramite web non funzionasse:
- all'interno di Visual Studio Code, cliccare sul pulsante delle estensioni nella barra di sinistra (è l'ultimo del primo gruppo)
- nel campo di ricerca, digitare
php debug
- selezionare l'estensione di nome
PHP Debug
realizzata dal'autoreXdebug
- cliccare sul pulsante
Installa
Procedi poi ad aprire, tramite Visual Studio Code, la cartella locale che contiene il codice del nostro progetto
Passo 4: Creare una configurazione di debug
Dalla colonna di sinistra, clicchiamo sul pulsante con l'icona del play con il bug. Dalla colonna apertasi, cliccare il link creare un file launch.json
Questo crea automaticamente la cartella .vscode
e, al suo interno, il file launch.json
. Detto file viene automaticamente aperto all'interno di Visual Studio Code, e contiene due configurazioni pronte all'uso:
Listen for Xdebug
: rimane in attesa di una connessione da XdebugLaunch currently open script
: avvia lo script corrente per il debugging
La seconda configurazione funziona solamente con le applicazioni più semplici, motivo per cui non è molto utile (io di solito la elimino completamente). La prima, quella di nome Listen for Xdebug
, è quella realmente importante.
Passo 5: Modificare la porta
Per impostazione predefinita, la configurazione creata presenta l'opzione "port": 9000
. Questo è un retaggio del vecchio Xdebug 2, e non funziona con il nuovo Xdebug 3. Affinché la sessione di debugging possa svolgersi correttamente, dobbiamo modificare tale valore in "port": 9003
Le versioni moderne dell'estensione utilizzano il valore corretto di default. È comunque fondamentale verificarlo esplicitamente
Passo 6: Specificare i percorsi (pathMappings)
Se il PC sul quale programmiamo e utilizziamo Visual Studio Code è lo stesso che esegue l'interprete PHP e non stiamo usando Docker, Vagrant o altre soluzioni di virtualizzazione, possiamo proseguire oltre.
In tutti gli altri casi, dobbiamo "mappare" il percorso che contiene i file sul server PHP con quello locale. Questo è necessario affinché Visual Studio Code possa mostrare il file "giusto" durante il debugging.
Allo scopo, aggiungiamo un'opzione subito dopo alla direttiva name
:
"pathMappings": {
"/percorso/file/sul/server/php/": "${workspaceRoot}"
},
Chiaramente dobbiamo sostituire a "/percorso/file/sul/server/php/"
il reale percorso che contiene i file PHP sul PC o server che eroga i file. Se detto sistema impiega Linux, sarà probabilmente qualcosa di simile a "/var/www/html"
oppure, se il tutto è stato installato seguito la nostra guida ad Apache/nginx+PHP, "/home/web/local"
.
Per quanto riguarda la seconda parte, mettiamo sempre lo specifico valore "${workspaceRoot}"
per indicare la cartella che abbiamo aperto nell'IDE alla fine del precedente Passo 3
. Non dovrebbe essere necessario aggiungere altro.
Passo 7: Sospensione all'avvio (stopOnEntry)
Trovo sia molto importante aggiungere la direttiva che fa sì che l'esecuzione venga sospesa automaticamente sulla primissima riga del primo file PHP eseguito. Allo scopo, aggiungiamo questa nuova opzione subito dopo alla direttiva type
:
"stopOnEntry": true,
In seguito, quando avremo verificato che tutto funzioni correttamente, potremo commentare questa direttiva anteponendovi due slash (//
).
Passo 8: Salvare il file
La configurazione è ora terminata. Non dimentichiamo di salvare il nostro file launch.json
(combinazione da tastiera: Ctrl+S
) e poi di chiuderlo.
In caso, successivamente, volessimo apportare qualche modifica, basterà aprire di nuovo il file .vscode/launch.js
tramite Visual Studio Code.
Passo 9: Avviare la sessione dei debug
Ora è tutto pronto: possiamo avviare la sessione di debug! Allo scopo, basta battere F5
sulla tastiera, oppure selezionare la voce di menu Esegui -> Avvia debug
. Se stiamo usando Windows, Windows Firewall ci chiederà di autorizzare l'applicazione. Spuntiamo entrambe le caselle e confermiamo
» Leggi anche: TLI risponde: cosa significa che "Windows Firewall ha bloccato alcune funzionalità di questa app"?
Visual Studio Code entra così in modalità "ascolto" (listening). Sta cioè attendendo che Xdebug si connetta per iniziare l'attività di debugging.
Per far sì che questo accada, è sufficiente aprire il browser web e... navigare il nostro sito! Poiché abbiamo configurato il debugger di modo che si fermi alla prima riga, l'esecuzione dovrebbe essere immediatamente sospesa
In caso l'esecuzione proceda come al solito, senza che lo script si fermi sulla prima riga, qualcosa non sta funzionando. Ho proposto alcune idee per la risoluzione in quest'altro approfondimento:
Se invece l'esecuzione si è correttamente fermata sulla prima riga, significa che tutto è stato configurato correttamente. Dallo stato di sospensione attuale possiamo fare tante cose belle.
Passo 10: Variabili e stack delle chiamate
Per prima cosa, rivolgiamo l'attenzione in alto a sinistra, nel riquadro VARIABILI
. Qui vengono visualizzate tutte le variabili definite dall'applicazione, con il relativo valore. Nell'esempio seguente, ad esempio, abbiamo $date
e $name
ma, poiché non è ancora stato assegnato alcun valore, Visual Studio Code le mostra come uninitialized
Espandendo il gruppo Superglobals
troviamo le altre variabili fornite di default da PHP: $_GET
, $_POST
, $_COOKIE
eccetera, mentre User defined constants
raggruppa eventuali costanti.
Scendendo più in basso, il gruppo ESPERESSIONE DI CONTROLLO
permette di aggiungere dei "watch", ovvero variabili ed espressioni che desideriamo tenere sott'occhio. Il loro valore verrà mostrato qui e aggiornato automaticamente mano a mano che proseguiremo con l'esecuzione dello script PHP
Ancora più sotto c'è lo STACK DI CHIAMATE
. Qui viene mostrato il flusso delle chiamate alle varie funzioni e l'invocazione dei metodi. In pratica, si parte sempre con un {main}
che costituisce la pagina principale, poi ogni riga indica una chiamata di funzione. Oltre ad aiutarci a capire il flusso del programma ("chi chiama chi"), questa sezione è utilissima perché possiamo sempre cliccare sulle singole righe per aprire automaticamente il file che contiene il codice in questione e saltare immediatamente alla riga in cui è avvenuta la chiamata
Passo 11: Breakpoint e avanzamento a step
L'ultima sezione in basso a sinistra elenca i breakpoint, ovvero le condizioni e i punti in cui l'esecuzione dello script PHP deve essere sospesa per consentirci di ispezionare le variabili, lo stack delle chiamate e lo stato dell'applicazione. Oltre alle condizioni "generali" per fermarsi sui vari tipi di warning e/o error, vengono riportati anche i breakpoint che abbiamo impostato noi.
Per impostare un breakpoint con Visual Studio Code è sufficiente:
- aprire il file che contiene il punto in cui vogliamo sospendere l'esecuzione dell'applicazione
- individuare la riga alla quale vogliamo sospendere l'esecuzione
- cliccare sullo spazio vuoto che si trova subito prima al numero di riga in questione
Apparirà così un pallino rosso, segnale che il breakpoint è impostato
Ora che abbiamo capito come inserire un breakpoint, dobbiamo prendere confidenza con la piccola barra di controllo in alto
I pulsanti permettono di avanzare con l'esecuzione del programma in vari modi:
Continua
(da tastiera:F5
): continua con l'esecuzione, fermandosi solo al breakpoint successivo. Se non è definito alcun breakpoint dopo la posizione corrente, l'applicazione procede fino alla fineEsegui istruzione/routine
(F10
): esegue la prossima istruzione, poi si ferma di nuovo. Questo è il comando che useremo più spesso per avanzare "un passo alla volta"Esegui istruzione
(F11
): è simile al precedente, ma con una sostanziale differenza. Se la prossima istruzione è una chiamata a funzione oppure l'invocazione di un metodo, il debugger entra nel codice in questione, poi si ferma di nuovo, di modo che sia possibile procedere con l'esecuzione a step della funzione/metodo in questione. Questo è l'altro comando che useremo spessoEsci da istruzione
(MAIUSC+F11
): procede nell'esecuzione della funzione/metodo corrente, poi esce e si ferma di nuovo.Riavvia
: ricarica la pagina e riavvia la sessione di debug - nella mia esperienza, non sono mai riuscito a farlo funzionare correttamente. Allo scopo, uso quindiArresta
poi ricarico la pagina del browserArresta
: termina la sessione di debug
Passo 12: Breakpoint condizionali
Immaginiamo di eseguire un lungo ciclo for
su centinaia di migliaia di valori. Uno di questi valori causa problemi al resto dell'applicazione, e vorremmo esaminare il perché tramite il debugger. Raggiungere il punto in cui si verifica la condizione specifica con i breakpoint "normali" sarebbe estremamente noioso, perché dovremmo manualmente ispezionare, appunto, centinaia di migliaia di valori prima di trovare quello giusto. Per gestire questa necessità si usano i breakpoint condizionali, che sospendono l'esecuzione solo quando si verifica una determinata condizione.
Per inserire un breakpoint condizionale con Visual Studio Code:
- fare click con il pulsante destro del mouse sullo spazio vuoto che si trova subito prima del numero di riga
- scegliere
Aggiungi punto di interruzione condizionale
- nel campo sottostante, digitare l'espressione che, quando vera, sospende l'esecuzione
- battere
Invio
per confermare
Nell'esempio sottostante ho inserito un breakpoint condizionale alla riga 18 sulla condizione $name == "zane"
. Poiché la variabile è stata così valorizzata alla precedente riga 8, l'esecuzione verrà sospesa
Conclusioni
In questa guida abbiamo visto come eseguire il debug del codice PHP in Visual Studio Code tramite Xdebug. La vera complessità dell'operazione risiede nella corretta configurazione e integrazione di Xdebug con l'interprete PHP. Da lì in poi, però, la configurazione di Visual Studio Code è piuttosto semplice, e va svolta soltanto la prima volta per ogni progetto.
Buon debugging!