Was ist Debugging?

Debugging ist Teil des Reverse Engineerings klassischen Softwareentwicklung.

Dabei bekommen wir sowohl als Entwickler einer eigens entwickelten Anwendung als auch bei einer Anwendung einer anderen Person einen tieferen Einblick in die Prozesse und Arbeitsprozesse. Dies bietet die Option Anwendungsabläufe leichter zu verstehen und mögliche Fehler schneller zu beseitigen, da der Anwender z.B. immer aktuelle Details zu verfügbaren Variablenzuweisungen und Ressourcen einsehen kann.

Debugging kann zum Ausführungszeitpunkt eines Jobs, einer Webanfrage oder Benutzerinteraktion, sowie während des Durchlaufs eines Unit Tests geschehen.

Setzt ein Entwickler einen Haltepunkt (Breakpoint), teilt er dem Debugger damit mit, an welcher Stelle er pausieren soll. Genau dort hält der Debugger die Ausführung an. Er ist demnach ein Tool, das die Schnittstelle zwischen der Entwickler und der auszuführenden Anwendung darstellt und kann dadurch auch als Kontrollzentrum verstanden werden.

Welche Vorteile gibt es gegenüber Dumping?

Xdebug bietet schrittweises Debugging, Stack Tracing, Performance Profiling und Code-Coverage-Analyse. Gegenüber klassischen Ausgabefunktionen wie var_dump(), echo oder – im Kontext des Laravel PHP Frameworks – dd() liegt der Vorteil vor allem in der Flexibilität. Einfache Ausgabefunktionen liefern pro Aufruf nur einen einzelnen Schnappschuss des Prozesszustands.

Das reicht in vielen Fällen aus. Doch spätestens nach einer Änderung müssen wir den gesamten Prozess neu starten – erneut zur Stelle navigieren und die Anpassung mehrfach „blind“ testen, bis das Ergebnis stimmt. Das kostet Zeit und verlangsamt die Entwicklung spürbar.

Xdebug löst dieses Problem. Entwickler prüfen Änderungen live und validieren sie direkt – während die Anwendung weiterläuft. Greift die Änderung beim nächsten Schritt? Das zeigt Xdebug sofort. Kurzgesagt: Entwickler sparen Zeit, statt jede Änderung einzeln zu validieren.

Auch deshalb schafft es das Team bei der Digitalagentur mindtwo GmbH, Kunden schnell zum gewünschten Ergebnis zu bringen. Unit Tests validieren die Arbeit automatisiert spätestens beim nächsten Deployment in die Testinstanz. Pest sei Dank.

Feature Deep Dive

Dies geschieht anhand der IDE PhpStorm in einem Fallbeispiel, basierend auf der Ausführung eines Requests an den PHP Interpreter mit einem gewissen Pest (was seinerseits auf PhpUnit aufsetzt) Test Case.

Step Debugging

Eingangs wurden ja bereits Breakpoints angesprochen, die wir selbst in der IDE setzen können, um an bestimmten Punkten in der jeweiligen Anwendung die Ausführung dessen zu pausieren.

Mit der folgender php.ini Konfiguration können wir das Profiling aktivieren (dieser manuelle Step wird, beim Setup mit Herd, explizit nicht benötigt, es wird schon „automagically“ in Verbindung mit PhpStorm und anderen Editoren entsprechend vorbereitet/genutzt):

xdebug.mode = develop,debug

Es ist dabei außerdem wichtig, dass wir nicht nur einen, sondern auch direkt mehrere Breakpoints setzen können. Diese können auch mit weiteren Konditionen ausgestattet werden, zu welchem Zeitpunkt diese wirklich die Ausführung pausieren sollen.

Es ist also z.B. möglich, dass ein gewisser Breakpoint auch nur dann die Ausführung pausiert, sobald eine gewisse Gleichung den Wert true ergibt.

Da Breakpoints somit sehr vielseitig eingesetzt werden können und die Ausführung pausieren, ist es immer von Mehrwert, dass wir uns Gedanken machen, wann es wirklich sinnvoll ist, einen Breakpoint zu setzen. „Mit viel Macht kommt viel Verantwortung“, und so.

Sobald wir einen Breakpoint gesetzt haben, können wir auch die weitergehenden Konditionenen definieren:

  1. Der normale Dialog, beim Klicken auf einen solchen gesetzten Breakpoint:

Detailansicht eines gesetzten Breakpoints in PhpStorm mit Optionen für „Enabled“, „Suspend execution“ und einem Eingabefeld für Bedingungen

  1. Der Dialog wenn wir im vorherigen Popover auf „More“ klicken, bei dem wir das Verhalten des Breakpoints noch weiter anpassen können:

Das Einstellungsmenü für Breakpoints in PhpStorm, das zusätzliche Funktionen wie Log-Nachrichten, Stack Traces und die Option „Remove once hit“ zeigt

Breakpoints sind ein mächtiges Werkzeug des Debuggings, um „laserfocused“ durch eine Anwendung zu springen und sich die gewünschten Momentaufnahmen einer herausgesuchten Stelle ohne Umstände direkt ansehen zu können.

Eine aktive Debugging-Sitzung in PhpStorm, bei der die Code-Ausführung an einem Breakpoint pausiert und verfügbare Variablen wie $this, $user und $event im Debug-Fenster angezeigt werden

Zudem ist in diesem Screenshot auch einsehbar, welche Steueroptionen zur Verfügung stehen, wie das Continue, Step Over, Step Into und Step Out (Of), um innerhalb einer aktiven Debugging Session zu navigieren.

Natürlich sind dabei auch alle klickbaren Elemente via Keyboard Shortcuts nutzbar, mit und ohne installiertem IdeaVIM Plugin.
Da jedoch jedes Keyboard Mapping unterschiedlich ist, und die originale Dokumentation von JetBrains bereits auf die Standardeinstellungen eingeht, wäre es wenig hilfreich hier weiter in die Details dazu einzutauchen – und so bleibt dies eine Aufgabe, die wir selbst meistern dürfen.

Stack Traces

Auch via PhpStorm ist es möglich, einen Stack Trace oder Thread Dump zu nutzen.

Dafür müssen wir jedoch erst einmal einen solchen zur Verfügung haben und, was auch Teil der Einstellungen von Xdebug ist, damit dieses eben jenes anlegt.

Mit der folgender php.ini Konfiguration können wir das Profiling aktivieren:

xdebug.mode \= develop,trace  
; 0=human readable, 1=machine readable, 2=HTML  
xdebug.trace\_format \= 1  
; %c=crc, %p=pid  
xdebug.trace\_output\_name \= trace.%c.%p

Das Output Directory von Xdebug sollte standardmäßig /var/tmp sein.

Der Vorteil eines Stack Traces ist, schnell und gezielt den immer selben Prozessablauf zu durchlaufen und somit direkt an den immer selben bestimmten Punkt in einer Anwendung zu gelangen.

Dateien sind, der obrigen Konfiguration nach, im folgenden Schema benannt:
trace.%c.%p

Dieser kann unter den DEV-Teams geteilt werden und es lässt sich durch dessen wiederholbare Ausführung Zeit sparen, bevor wir uns z.B. erst selbst an die jeweiligen Stellen vorarbeiten und das benötigte Setup vorbereiten.

Des Weiteren ist es möglich, direkt an die jeweilige Stelle im Source Code der Anwendung zu springen, sobald PhpStorm den Stack Trace ausgeführt und die die Anwendung soweit „vorbereitet“ hat.

Anbei ein allgemeines Beispiel für dessen Anwendung, nach Aufnahme beim Aufruf des Index (/) einer Filament Anwendung (return view(...)):

Ein im Terminal ausgegebener Xdebug-Stacktrace, der den zeitlichen Ablauf und die Hierarchie der aufgerufenen PHP-Funktionen detailliert protokolliert

Performance Profiling

Das Performance Profiling schreibt den gesamten Verlauf eines Requests an den PHP Interpretermit Timings und Memory Usage.

Mit der folgender php.ini Konfiguration können wir das Profiling aktivieren:

xdebug.mode \= develop,profile

Das Output Directory von Xdebug sollte standardmäßig /var/tmp sein.

Mit Tools wie K/Qcachegrind ist es möglich, die dadurch generierten cachgrind.\* Dateien leicht einzusehen.

Zum Installieren unter macOS kann brew install qcachegrind verwendet werden.
Aber Achtung: Aktuell ist der Aufruf nur via Terminal möglich, z.B. via qcachegrind.

Außerdem gestaltet sich die Nutzbarkeit der Anwendung unter macOS als… interessant.

Sofern der Pfad zur Datei beim Aufruf via Terminal mit angefügt wird, friert die Anwendung ein und ist nicht responsiv, auch wenn die Datei anscheinend korrekt geladen worden ist.

Das Öffnen der Anwendung ohne vorherige Übergabe eines Dateipfades führt nicht zu diesem Fehlverhalten. Das gilt auch dann, wenn wir nachträglich eine Datei öffnen, die zuvor aus einem .gz Archiv extrahiert wurde.

Weiteres Troubleshooting geht jedoch weit über den Rahmen des Blogartikels hinaus.

Es empfiehlt sich jedoch leider allgemein, bei der Navigation durch das Tool, die Maus statt der Tastatur. Es wirkt als stecke das Tool noch vor jeglicher a11y-Nutzungsoffensive fest.

Ein Beispiel – nach der Konfiguration dessen in Xdebug – ist nachfolgend einzusehen.

  1. Via der Anwendung unter macOS:

Die Analyse einer Cachegrind-Datei in qcachegrind, die den Speicherverbrauch und die Aufrufzeiten einzelner PHP-Methoden zur Performance-Optimierung visualisiert

Es ist leicht einsehbar, wie viele Calls und Resourcen insgesamt der Aufruf einzelner Methoden eines durchgelaufenen Requests an den PHP Interpreter verursacht hat.

  1. Schlussendlich noch via Dateiinhalt selbst:

    version: 1  
    creator: xdebug 3.4.0alpha2-dev (PHP 8.4.19)  
    cmd: /Applications/Herd.app/Contents/Resources/valet/dump-loader.php  
    part: 1  
    positions: line
    
    events: Time\_(10ns) Memory\_(bytes)
    
    fl=(1) php:internal  
    fn=(1) php::getenv  
    1 75 0
    
    fl=(2) xdebug://debug-eval  
    fn=(2) {main}  
    1 7642 32  
    cfl=(1)  
    cfn=(1)  
    calls=1 0 0  
    1 75 0
    
    fl=(2)  
    fn=(2)  
    1 2658 0
    
    fl=(2)  
    fn=(2)  
    1 46 0
    
    fl=(2)  
    fn=(2)  
    1 33 0
    
    fl=(3) /Applications/Herd.app/Contents/Resources/valet/HerdConfiguration.php  
    fn=(3) require\_once::/Applications/Herd.app/Contents/Resources/valet/HerdConfiguration.php  
    1 150 0
    
    fl=(1)  
    fn=(4) php::array\_key\_exists  
    48 5108 0
    
    fl=(1)  
    fn=(5) php::php\_uname  
    182 1371 32
    
    fl=(1)  
    fn=(6) php::strpos  
    182 1329 0
    
    fl=(3)  
    fn=(7) BeyondCode\\HerdConfiguration\\HerdConfiguration→detectOperatingSystem  
    181 115538 40  
    cfl=(1)  
    cfn=(5)  
    calls=1 0 0  
    182 1371 32  
    cfl=(1)  
    cfn=(6)  
    calls=1 0 0  
    182 1329 0
    
    fl=(1)  
    fn=(4)  
    225 25 0
    
    \[…\]
    

(Dies ist stark gekürzt und macht gerade einmal ca. 3% des gesamten Dateiinhalts aus und ist auch der Grund, warum jegliche cachegrind\-Datei so groß ist und die Generierung jener so lange dauert.)

Diesertage ist der Ansatz, dies alles via Xdebug herauszufinden, vermutlich aber auch schlicht durch die mögliche Nutzung von Herd Dumps sowie Herd Profiler oder der PHP Debug Bar bzw. Laravel Debug Bar überschattet. Deshalb kann dies vermutlich somit teilweise ignoriert werden, da zumindest die heutigen Alternativen deutlich performanter wirken.

Zeiten im Wandel durch AI

In Zeiten der vermehrten Nutzung von Agentic AI könnte man meinen, dass das eigenverantwortliche Debugging in den Hintergrund gerät. Einige gehen sogar soweit vorauszusagen, dass Entwickler, Designer oder Musiker bald nicht mehr benötigt werden. Im Netz kursieren etliche Workflows und Empfehlungen, bei denen Anwender nur noch ihre Befehle an die AI abgeben und die Resultate gegenprüfen müssen. Vereinzelt sind sogar Stimmen laut, die behaupten, auch den letzten Schritt könne man sich mit den richtigen Skills oder Prompts sparen.

Doch stimmt das wirklich?

Wir verstehen uns nicht einfach als Softwareentwickler, sondern auch ein Stück weit als Kreativschaffende. „Vibe Coding“ öffnet Nicht-Entwicklern vermeintlich die Türen zur Softwareentwicklung, doch die Ergebnisse sind mit Vorsicht zu genießen. Ungeprüfte Anwendungen führen immer wieder zu Sicherheitslücken und sind anfällig für Bugs. Deshalb sind wir davon überzeugt, dass das Schreiben von Code in die Hände von Experten gehört – ob mit oder ohne KI. Generierten Code zu erzeugen ist einfach. Ihn zu verstehen und zu validieren, ist die eigentliche Aufgabe.

Anwendung

Zur Verdeutlichung ein Beispiel in der Anwendung, anhand der Entwicklungsumgebung (IDE) PhpStorm. Hinweis: Es gibt selbstverständlich auch andere Möglichkeiten, Xdebug einzusetzen.

Laravel Herd

Da wir intern via macOS auf Laravel Herd (Pro) setzen, ist es naheliegend, Xdebug direkt darüber einzubinden. Windows-Nutzer haben dieselbe Option. Linux-Nutzer müssen sich allerdings weiterhin mit einer manueller Konfiguration über den Laravel Valet Port behelfen.

PhpStorm

Sobald Xdebug über Laravel Herd aktiviert ist, müssen in PhpStorm einige Schritte abgeschlossen werden, damit die Debug-Signale korrekt empfangen werden.

  1. Es empfiehlt sich dabei auch zuerst ein weiterer Blick in die Konfigurationsanleitung der Laravel Herd Dokumentation, um z.B. unerwünschte erzwungene Breakpoints von vornherein zu vermeiden.

  2. Danach bietet es sich an, die PHP Einstellungen für das aktuelle Projekt gegenzuprüfen.

  • Die allgemeinen PHP Einstellungen für das aktive Projekt seitens IDE

Das Konfigurationsmenü in PhpStorm für PHP-Sprachlevel 8.4 und den CLI-Interpreter

  • Die PHP CLI Interpreter Einstellungen

Das Konfigurationsmenü in PhpStorm für PHP-Sprachlevel 8.4 und den CLI-Interpreter

  • Die Server Einstellungen für das aktive Projekt

Detaillierte PHP-Interpreter-Einstellungen mit Pfaden zur PHP-Executable und der Konfigurationsdatei (php.ini) sowie der aktiven Xdebug-Version 3.4.0alpha2-dev

  1. Im nächsten Schritt bleibt nur noch das Aktivieren des Debug Modus in der IDE, welche sich im oberen Menü von PhpStorm befinden kann, je nach Version, Einstellung und Design.

Detaillierte PHP-Interpreter-Einstellungen mit Pfaden zur PHP-Executable und der Konfigurationsdatei (php.ini) sowie der aktiven Xdebug-Version 3.4.0alpha2-dev

Die offizielle JetBrains Dokumentation bietet eine ausführliche Anleitung zur manuellen Einrichtung ohne Laravel Herd. Dort wird auch in tieferem Detail den eigentlichen, manuellen Vorgang beschrieben, um Xdebug ohne ein Convenience Tool wie Laravel Herd einzurichten. Die Information bezüglich Browser Add-On/Extension kann aber je nachdem übersprungen werden.

Fazit vom Setup

Probleme beim Einrichten von Xdebug sind keine Seltenheit. Nicht alles funktioniert so, wie hier oder anderswo beschrieben.

Manchmal funkt das Betriebssystem wegen belegter Ports, DNS-Problemen oder weil Xdebug nicht korrekt angesprochen wird, dazwischen.

PHP-Projekte professionell aufsetzen und dabei auf bewährte Entwicklungs-Workflows setzen? Das Team von mindtwo unterstützt Sie dabei – von der Entwicklungsumgebung bis zum Deployment. Nehmen Sie gerne Kontakt auf.