[ITA] XDebug, il debug di PHP

XDebug ci aiuta nel debugging dei nostri script, permettendoci anche di migliorare le prestazioni.

Cos’è XDebug

Xdebug è una libreria professionale che consente di effettuare sia il profiling che il debug delle applicazioni web. Questo utilissimo strumento consente ai programmatori di risparmiare molto tempo nel testing del codice alla ricerca di errori; ma non svolge soltanto il compito di debugger, bensì consente di calcolare il tempo totale di compilazione o di esecuzione di un determinato script, testandone le prestazioni. XDebug è stato sviluppato dal programmatore olandese Derick Rethans, il debugger/profiler può essere utilizzato per correggere errori e/o migliorare le prestazioni su qualsiasi progetto, poiché non è essenziale utilizzarlo solo per i “progetti grandi” ma anche per i piccoli script, per renderli ancora più robusti e performanti. In questo articolo andremo ad installare XDebug, procederemo alla sua configurazione e mostreremo alcuni esempi pratici sull’utilizzo di questo strumento per chiarirvi meglio le idee.

Requisiti

La versione da noi utilizzata di XDebug (http://www.xdebug.org) è la 2.0dev, su un server Apache 1.33 con PHP 5.1.2. XDebug non ha dipendenze di alcun tipo con altri pacchetti, quindi può essere installato senza problemi.

Installazione

XDebug può essere utilizzato in tre modi:

  • Moduli DLL;
  • Moduli PECL;
  • Console.

Nella tabella qui sotto sono riportate le compatibilità con le diverse versioni di PHP:

PHP Version: PHP Api Version: Zend Module Api No: Zend Extension Api No: Recommended version:
4.2.3 20010901 20020429 20020429 1.0.0rc1
4.3.0pre2 20020307 20020429 20021010 1.1.0pre2
4.3.0rc1 20020918 20020429 20021010 1.1.0
4.3.0 20020918 20020429 20021010 1.2.0
4.3.1-4.3.5 20020918 20020429 20021010 1.3.1
4.3.7-4.3.8 20020918 20020429 20021010 1.3.2 / 2.0.0-cvs
5.0.0rc3 20031224 20040412 220040412 1.3.2 / 2.0.0-cvs
5.0.5 or later 20041225 20041030 220040412 2.0.0-beta5 or cvs
5.1.x 20041225 20050922 220051025 2.0.0-beta5 or cvs

Adesso andiamo a vedere come installare XDebug, se vogliamo installarlo tramite modulo PECL, dobbiamo eseguire l’installazione come qualsiasi pacchetto PECL/PEAR, tramite il comando:

pear install xdebug-beta

fare attenzione che dopo averlo installato bisogna aggiungere al file php.ini la riga:

zend_extension="/path/to/php/modules/xdebug.so"

L’utilizzo attraverso la console può essere fatto sia con o senza integrazione in un editor IDE, non staremo a soffermarci sull’utilizzo della console, ma approfondiremo soltanto attraverso l’uso dei moduli DLL. Per effettuare l’installazione del modulo DLL bisogna soltanto inserire nel file php.ini la seguente riga:

zend_extension_ts="/path/to/php/ext/php_xdebug.dll"

Una volta installato, il debugger è subito attivo. Per gestire anche il profiling di XDebug, scarichiamo ed installiamo KChacheGrind (per linux, http://kcachegrind.sf.net/) o WinCacheGrind (per windows, http://sourceforge.net/projects/wincachegrind).

Configurazione

Aggiungiamo le righe visibili nel Listing 1 al file php.ini.

[XDebug]
; Path of XDebug's extension
extension=php_xdebug.dll
xdebug.remote_enable=On
xdebug.remote_host=localhost
xdebug.remote_port=17869
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.profiler_enable=1
xdebug.profiler_output_dir="j:\xdebug\profiling"

Listing 1. Configurazione di XDebug nel php.ini

Esempi pratici

Il primo esempio che andremo a vedere è la gestione dell’opzione di visualizzazione degli errori (Listing 2).

if (!xdebug_is_enabled()) xdebug_enable();
// Abilito la visualizzazione degli errori
echo "Visualizzazione errori: <strong>" . ((xdebug_is_enabled() == 1) ? "ON" : "OFF") . "</strong>\n";

Listing 2. Visualizzazione degli errori Andiamo ad analizzare il codice l’istruzione xdebug_is_enabled restituisce un valore (1 o 0) in base allo stato di attivazione della visualizzazione degli errori, le funzioni xdebug_enable e xdebug_disable abilitano e disabilitano la visualizzazione. Il secondo esempio permette la visualizzazione dello stack di memoria relativo alle variabili utilizzare nello script (Listing 3).

class strings {
static function fix_strings($a, $b) {
foreach ($b as $item) { }
var_dump(xdebug_get_declared_vars());
}
}
strings::fix_strings(array(1,2,3), array(4,5,6));

Listing 3. Esempio sullo stack di memoria La funzione xdebug_get_declared_vars restituisce tutte le variabili utilizzate nello script con alcune informazioni su di esse. Il terzo esempio ci consente di catturare tutte le informazioni riguardo una chiamata a funzione (Listing 4).

function esempio($a) {
echo "Chiamata @ " . xdebug_call_file() . ":" . xdebug_call_line() . " da " . xdebug_call_function();
}
$value = esempio(array('XDebug'));

Listing 4. Gestione delle chiamate Analizzando il codice vengono utilizzate 3 funzioni native di XDebug: xdebug_call_filexdebug_call_linexdebug_call_function, rispettivamente svolgono i seguenti compiti:

  • la prima, restituisce il file da cui si effettua la chiamata;
  • la seconda, restituisce la linea da cui si effettua la chiamata;
  • la terza, restituisce la funzione da cui si effettua la chiamata.

Possiamo capire meglio il funzionamento attraverso lo studio dell’output prodotto dallo script:

Chiamata @ /path/to/Apache/htdocs/xdebug/call_methods.php:7 da {main}

Un caso reale

Adesso passiamo a qualcosa di più sostanzioso ed utile, l’utilizzo di XDebug su una classe che gestisce le informazioni di una rubrica. Diamo per scontato di avere la classe rubrica, che consente di aggiungere/modifica/eliminare i contatti ed inoltre consente la ricerca di quest’ultimi. Nel Listing 5 possiamo vedere come vengono gestite le informazioni dei contatti:

// faccio partire il code-coverage del codice
xdebug_start_code_coverage();
// creo l'istanza della classe
require 'class.rubrica.php';
$rub = new rubrica();
// aggiungo alcuni contatti
$rub->addContact(0, "Mario", "Rossi", "012345678", "9876543210");
$rub->addContact(1, "Mattxeo", "Bianchi", "123456789", "8765432109");
$rub->addContact(2, "Alfredo", "Neri", "234567890", "7654321098");
$rub->addContact(3, "Martina", "Rossi", "345678901", "6543210987");
// modifico il contatto n°1
$rub->modContact(1, "Matteo", "Bianchi", "123456789", "8765432109");
// elimino il contatto n°2
$rub->delContact(2);
// cerco tutti quelli che hanno come cognome Bianchi
var_dump($rub->search("Rossi", "cognome"));
var_dump(xdebug_get_code_coverage());

Listing 5. XDebug applicato ad una rubrica Il codice da analizzare è molto semplice, dopo aver inizializzato la classe rubrica inseriamo al suo interno alcuni contatti, ne modifichiamo il 2° poiché è errato, ed eliminiamo il contatto n° 3. Dopodiché ricerco all’interno tutti quelli che hanno come cognome “Rossi”. Attraverso le istruzioni xdebug_start_code_coverage e xdebug_get_code_coverage, che abbiamo già visto precedentemente, riesco a capire le istruzioni che sono ripetute più volte, e cercando di ottimizzarle riduco il tempo di esecuzione dello script. Analizziamo il risultato del profiling del codice con WinCacheGrind (Fig. 1). 

 Fig.1 possiamo notare che il software mostra il tempo di esecuzione totale e parziale delle istruzioni, nonché il numero di chiamate ad esse.

Riassunto

Il nostro articolo è giunto al termine, ma nonostante ciò XDebug non si limita soltanto alle funzioni visionate, ma ne ha un set composto da molte istruzioni che spaziano dal trace delle istruzioni eseguite al dumping delle variabile e delle funzioni, passando dalla gestione dello stack al code-coverage.