25.4 apd 

Besprochene Version: 1.0.1 | Lizenz: PHP-Lizenz 2.0.2 |
Die Abkürzung »apd« steht für »Advanced Profiler and Debugger«. apd ist ein Tool, mit dem Sie Fehler in Anwendungen eingrenzen und vor allem ein Profiling Ihrer Applikation durchführen können. Das heißt, Sie können feststellen, wie lange Funktionen laufen bzw. wo sich Flaschenhälse in Ihrer Applikation befinden.
Das primäre Ziel von apd ist inzwischen das Profiling geworden, so dass der Autor sich bei der Entwicklung darauf konzentriert hat.
Um zu erfahren, wie Ihre Applikation sich verhält, platzieren Sie in der ersten Zeile der PHP-Datei den Befehl apd_set_pprof_trace(). Diese Methode protokolliert automatisch Funktionsaufrufe und Zeitverbrauch mit und legt diese in einer Datei ab. Das Verzeichnis, in dem die Datei abgelegt werden soll, können Sie der Methode als Parameter übergeben oder in der PHP-Konfigurationsdatei php.ini festlegen. Hierzu geben Sie nach der Direktive apd.dumpdir ein Gleichheitszeichen und den absoluten Pfad zum Verzeichnis an, in dem gespeichert werden soll.
Für die nachfolgenden Beispiele würde dieser Code genutzt:
// apd starten apd_set_pprof_trace(); class DbConnector { private $con; public function __construct ($server, $db, $user, $pass) { $this->con=mysql_connect($server,$user,$pass); mysql_select_db($db,$this->con); } public function sql($sql) { return mysql_query($sql, $this->con); } } $db = new DbConnector('localhost','db','user','geheim'); $ret = $db->sql("SELECT * FROM mitarbeiter"); $ret2 = $db->sql("SELECT t1.vorname, t1.nachanme FROM mitarbeiter as t1, mitarbeiter as t2 WHERE t1.vorname = t2.vorname AND t2.vorname = 'Homer'");
Listing 25.2 Profiling mit apd
Die Daten werden bei Aufruf des Scripts automatisch erfasst und in eine Datei geschrieben. Der Name einer solchen Datei beginnt mit pprof und endet auf die PID des Prozesses. Die hier enthaltenen Daten sind nicht dafür gedacht, direkt betrachtet zu werden. apd bringt ein Programm namens pprofp mit, das die Daten aufbereiten und ausgeben kann. pprofp erwartet einen Parameter, mit dem Sie definieren können, wie die Daten aufbereitet werden sollen. Möchten Sie die Funktionsaufrufe inklusive der verbrauchten Zeit der Reihe nach ausgeben lassen nutzen Sie den Parameter T, um eine Ausgabe als Baum zu erzielen, und den Parameter c, um die Zeiten ausgeben zu lassen.
> pprofp -Tc pprof.12142.0 0.00 main 0.00 apd_set_pprof_trace 0.00 DbConnector->__construct 0.00 mysql_connect 0.01 mysql_select_db 0.01 DbConnector->sql 0.01 mysql_query 0.01 DbConnector->sql 0.01 mysql_query Trace for /home/public_html/apd1.php Total Elapsed Time = 0.01 Total System Time = 0.00 Total User Time = 0.01
Listing 25.3 Ausgabe von pprofp
Wie Sie sehen können, werden die Funktionsaufrufe der Reihe nach ausgegeben. Funktionen, die von einer anderen Funktion oder Methode aufgerufen werden, sind jeweils ein wenig weiter eingerückt. Da das Beispiel nicht sehr umfangreich ist, finden Sie bei einigen Aufrufen eine Zeit von 0.00 Sekunden. Natürlich haben auch diese Aufrufe Zeit verbraucht, aber sie war einfach zu kurz, um hier aufzutauchen. In so einem Fall kann es hilfreich sein, wenn Sie die Funktion oder Methode mehrere hundert Mal aufrufen, um eine valide Zahlenbasis zu erhalten. Das Programm pprofp rufen Sie dann am besten mit dem Parameter R auf. In dem Fall erhalten Sie eine Ausgabe, bei der die Daten pro Funktion bzw. Methode kumuliert wurden und die Ausgabe alphabetisch sortiert ist. In dieser Ansicht finden Sie auch den benötigten Arbeitsspeicher und andere hilfreiche Informationen. Weitere Parameter finden Sie, wenn Sie pprofp ohne Parameter aufrufen.
Sollten Sie eine Auswertung der Daten mithilfe des Programms KCachegrind bevorzugen, ist das auch kein Problem. In dem Fall nutzen Sie anstelle von apd_set_pprof_trace() den Befehl apd_set_browser_trace() und erhalten eine Datei, die zu KCachegrind kompatibel ist.
Um ein einfaches Debugging durchzuführen, sind die Funktionen override_function() und rename_function() sehr hilfreich.
Die Funktion override_function() ist in der Lage, eine PHP-Funktion mit eigenem Code zu überschreiben. Sie bekommt als ersten Parameter den Namen der Funktion übergeben, unter dem der Code aufrufbar sein soll. Der nächste Parameter ist die Liste der Parameter, die als String übergeben wird, also beispielsweise als '$a, $b'. Als dritter und letzter Parameter wird der eigentliche Code der Funktion übergeben.
Falls Sie beispielsweise der Funktion strlen() nicht über den Weg trauen und durch eigenen Code testen wollen, ob der Rückgabewert der Funktion korrekt ist, könnten Sie das so machen:
echo strlen('Langer Text'); // Ausgabe 11 override_function ('strlen','$str','$i=0; while (isset($str{$i++})); return --$i;'); // Aufruf des neuen strlen() echo strlen('Langer Text'); // Ausgabe 11
Listing 25.4 Nutzung von override_function( )
rename_function() kann eine Funktion umbenennen. Der »alte Name« der Funktion wird als erster Parameter übergeben und der gewünschte, neue Name als zweiter Parameter. Das ist immer dann hilfreich, wenn Sie eine bestehende Funktion durch eine andere ersetzen wollen, wobei die ursprüngliche Funktion aber nicht verloren gehen soll. So etwas könnte so aussehen:
function my_strlen($str) { // Aufruf der "alten" Funktion strlen $laenge = old_strlen($str); // Speichern der Daten zum Debugging file_put_contents('daten.txt', "Uebergeben: $str\nLaenge: $laenge\n\n"); return $laenge; } // Umbenennen der "alten" Funktion in old_strlen rename_function ('strlen','old_strlen'); // Umbenennen der eigenen Funktion in strlen rename_function ('my_strlen','strlen'); // Urspruenglicher, "komplexer" Code, der strlen nutzt echo strlen ('langer Text');
Listing 25.5 Nutzung von rename_function( )
Darüber hinaus können Sie auch ein Debugging durchführen, bei dem apd sich mit einem Socket verbindet, den Sie dann beispielsweise mit einem Programm wie TcpListen auslesen können. In dem Fall müssten Sie den Vorgang mit apd_set_session_trace_socket() starten. Auch ist es möglich, mit apd_breakpoint() Unterbrechungen einzufügen oder eine Nachricht mit apd_echo() an den Socket zu senden. Allerdings denke ich, dass diese Vorgehensweise recht aufwändig ist, so dass ich Ihnen in so einem Fall eher einen Debugger wie Xdebug empfehle oder einen, wie er im Zend Studio enthalten ist.