PhpStorm, Xdebug und Logs kombinieren
Wer in Docker-Containern nur mit var_dump und Logs debuggt, schöpft das Potential der Entwicklungsumgebung nicht aus. Xdebug 3 mit PhpStorm verbindet den Debugger direkt mit dem Container – für echte Breakpoints, Variable-Inspektion und Stack Traces ohne einen einzigen var_dump().
Inhaltsverzeichnis
- 1. Warum Xdebug in Container-Setups andere Konfiguration braucht
- 2. Xdebug 3 im PHP-FPM-Container konfigurieren
- 3. PhpStorm Server und Path Mappings einrichten
- 4. Breakpoints setzen und Debug-Session starten
- 5. Variablen, Watch Expressions und Evaluate
- 6. Stack Traces und Call Stack in PhpStorm lesen
- 7. Container-Logs und Debugger kombinieren
- 8. CLI-Debugging: Magento-Kommandos debuggen
- 9. var_dump vs. Xdebug: direkter Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum Xdebug in Container-Setups andere Konfiguration braucht
In einer traditionellen Entwicklungsumgebung, in der PHP direkt auf dem Host läuft, verbindet sich Xdebug einfach mit der IDE über localhost. In Docker-Containern ist das grundlegend anders: Der Container ist eine isolierte Netzwerkumgebung, und localhost im Container ist nicht der Host. Xdebug muss wissen, unter welcher IP-Adresse die IDE (PhpStorm) erreichbar ist – und diese Adresse ist je nach Betriebssystem und Docker-Konfiguration unterschiedlich.
Auf Linux-Systemen mit Docker ist der Host typischerweise unter der Gateway-IP des Docker-Netzwerks erreichbar, häufig 172.17.0.1 oder der IP des docker0-Interfaces. Auf macOS und Windows stellt Docker Desktop den speziellen DNS-Namen host.docker.internal bereit, der automatisch auf die Host-IP auflöst. Mark Shustes Docker-Magento-Setup nutzt unter Linux eine Kombination aus Netzwerkkonfiguration und Environment-Variablen, um dieses Problem zu lösen – die Datei compose.dev-linux.yaml enthält die passende Xdebug-Konfiguration.
Xdebug 3 hat gegenüber Xdebug 2 ein komplett überarbeitetes Konfigurationsschema. Die alten xdebug.remote_*-Direktiven sind durch das neue xdebug.client_*-Schema ersetzt worden. Wer Konfigurationen aus Xdebug-2-Zeiten kopiert, wird sich wundern, warum keine Verbindung zustande kommt – die alten Direktiven werden in Xdebug 3 stillschweigend ignoriert. Der Wechsel zu xdebug.client_host und xdebug.client_port ist der häufigste Fix für "Xdebug verbindet nicht"-Probleme.
2. Xdebug 3 im PHP-FPM-Container konfigurieren
Die Xdebug-Konfiguration für PHP-FPM-Container erfolgt über eine INI-Datei, die in das Image gebaut oder als Volume eingehängt wird. Für Mark Shustes Docker-Magento-Setup liegt die Datei unter src/dev/php/xdebug.ini und wird beim Container-Start geladen. Die wichtigsten Direktiven für Xdebug 3: xdebug.mode auf debug (oder develop,debug für erweiterte Entwicklungshelfer), xdebug.client_host auf die Host-IP, xdebug.client_port auf 9003 (Xdebug-3-Standard), und xdebug.start_with_request=yes für automatischen Debug-Start oder trigger für On-Demand-Debugging.
Für die Produktion oder Environments mit Leistungsanforderungen empfiehlt sich xdebug.mode=off. Xdebug deaktiviert mit mode=off ist faktisch ohne Performance-Impact, weil die Extension zwar geladen, aber kein Profiling oder Debugging durchgeführt wird. In Magento 2 ist der Unterschied messbar: Eine Seite, die mit xdebug.mode=debug und aktivem Tracing 800ms lädt, lädt mit mode=off deutlich schneller. Für das Entwicklungs-Setup empfiehlt sich daher start_with_request=trigger, sodass Xdebug nur bei Requests mit dem speziellen Cookie oder Query-Parameter aktiv wird.
Die Umgebungsvariable PHP_IDE_CONFIG mit dem Wert serverName=projektname ist eine oft vergessene, aber kritische Konfiguration. Diese Variable teilt Xdebug mit, welchen Server-Namen er in der IDE-Kommunikation angeben soll. PhpStorm nutzt diesen Server-Namen, um die Path Mappings zu finden – ohne passenden Server-Namen funktionieren die Breakpoints nicht, obwohl die Verbindung scheinbar etabliert ist.
; src/dev/php/xdebug.ini — Xdebug 3 for Docker + PhpStorm
; For Xdebug 2: use xdebug.remote_* directives instead
[xdebug]
; Load Xdebug (add this line to php.ini or zend_extension= in xdebug.ini)
; zend_extension=xdebug
; Mode: debug for step debugging, develop for var_dump enhancement
xdebug.mode = debug
; Start debug session with XDEBUG_SESSION cookie or query param
; Use 'yes' to start with every request (slower, not recommended)
xdebug.start_with_request = trigger
; IDE host — host.docker.internal resolves on macOS/Windows
; On Linux: use gateway IP (172.17.0.1) or set via compose env
xdebug.client_host = host.docker.internal
xdebug.client_port = 9003
; Server name — must match PhpStorm Server configuration name
; Set via docker-compose environment: PHP_IDE_CONFIG=serverName=mironsoft
xdebug.idekey = PHPSTORM
; Increase timeout for slow Magento requests
xdebug.connect_timeout_ms = 2000
; Show full variable values (useful for large Magento arrays)
xdebug.var_display_max_depth = 5
xdebug.var_display_max_children = 256
xdebug.var_display_max_data = 1024
3. PhpStorm Server und Path Mappings einrichten
Unter Settings → PHP → Servers legt man einen neuen Server an. Der Name muss exakt mit dem Wert in PHP_IDE_CONFIG=serverName=NAME übereinstimmen. Host ist localhost (oder die Domain des Projekts), Port 80 (oder der gemappte Nginx-Port). Der wichtigste Teil: Path Mappings. Hier ordnet man dem lokalen Pfad (z.B. /home/mir/development/mironsoft/src) den Pfad im Container zu (z.B. /var/www/html).
Ohne korrekte Path Mappings findet PhpStorm die Dateien nicht, wenn Xdebug einen Breakpoint meldet. Das äußert sich darin, dass PhpStorm beim ersten Breakpoint eine Datei aus dem Container anzeigt, die nicht mit der lokalen Kopie identifiziert werden kann. PhpStorm fragt dann, ob man die Datei manuell zuordnen möchte – das ist der manuelle Weg. Der saubere Weg ist, die Path Mappings vorab vollständig zu konfigurieren, damit PhpStorm bei jedem Breakpoint sofort die korrekte lokale Datei öffnet.
Für Magento 2 mit Vendor-Packages ist zusätzlich darauf zu achten, dass auch der Vendor-Pfad gemappt ist. Breakpoints in Magento-Core-Dateien oder Drittanbieter-Modulen funktionieren nur, wenn PhpStorm den Container-Pfad /var/www/html/vendor/ auf den lokalen src/vendor/-Pfad mappen kann. Wer regelmäßig in Core-Code debuggt, sollte die Path Mappings initial einmal vollständig einrichten und dann als XML-Konfiguration exportieren.
4. Breakpoints setzen und Debug-Session starten
Breakpoints setzt man in PhpStorm per Klick auf den Zeilennummern-Gutter links neben dem Code. Ein roter Punkt erscheint, und PhpStorm pausiert die Ausführung, wenn diese Zeile erreicht wird. Das Debug-Listening muss aktiv sein – entweder über das Telefon-Icon in der Toolbar ("Start Listening for PHP Debug Connections") oder via Run → Start Listening for PHP Debug Connections. PhpStorm lauscht dann auf Port 9003 auf eingehende Xdebug-Verbindungen.
Die Debug-Session wird ausgelöst, wenn ein HTTP-Request mit dem Xdebug-Trigger-Cookie (XDEBUG_SESSION=PHPSTORM) oder dem Query-Parameter (?XDEBUG_SESSION_START=PHPSTORM) beim Server ankommt. Das Browser-Plugin "Xdebug Helper" (verfügbar für Chrome und Firefox) setzt diesen Cookie mit einem Klick. Alternativ kann man in PhpStorm eine Run-Konfiguration vom Typ "PHP Remote Debug" erstellen, die einen vorbereiteten Browser-Request mit dem richtigen Cookie auslöst.
Wenn PhpStorm die Verbindung empfängt und den Breakpoint findet, pausiert die Ausführung und das Debugger-Fenster öffnet sich automatisch. Man sieht den aktuellen Ausführungspunkt im Code, die Variablen im aktuellen Scope, den Call Stack und kann mit den Navigations-Buttons (Step Over, Step Into, Step Out, Resume) durch den Code navigieren. Conditional Breakpoints erlauben das Pausieren nur unter bestimmten Bedingungen – z.B. nur wenn $productId === 42 – um nicht bei jedem Loop-Durchlauf zu stoppen.
5. Variablen, Watch Expressions und Evaluate
Das Variablen-Panel im Debugger-Fenster zeigt alle Variablen im aktuellen Scope: lokale Variablen der Funktion, $this mit allen Properties des Objekts, und globale Variablen. Für Magento 2, das stark mit Dependency Injection und komplexen Objektgraphen arbeitet, ist diese Übersicht besonders wertvoll. Man sieht nicht nur den Variablenwert, sondern kann in Objekte hinein navigieren – Klick auf ein Objekt expandiert seine Properties, rekursiv bis zur konfigurierten Tiefe.
Watch Expressions erlauben das Beobachten bestimmter Ausdrücke über mehrere Breakpoints hinweg. Man gibt einen PHP-Ausdruck ein – z.B. $this->config->getValue('general/store_information/name') – und PhpStorm wertet diesen Ausdruck bei jedem Pausieren im Debugger aus. So kann man Werte verfolgen, die in einer Funktion berechnet, aber in einer anderen verwendet werden, ohne bei jedem Schritt manuell zu suchen.
Das Evaluate-Feature (Tastenkürzel Alt+F8) erlaubt das Ausführen beliebiger PHP-Ausdrücke im aktuellen Kontext. Man kann Methoden aufrufen, Werte setzen, Bedingungen testen – direkt zur Laufzeit, ohne den Code zu ändern. In Magento 2 kann man damit beispielsweise prüfen, ob ein Repository-Aufruf die erwarteten Daten zurückgibt, oder den Zustand des Caches abfragen, ohne die Debugging-Session zu unterbrechen.
<?php
// Example: Debugging a Magento 2 ViewModel with PhpStorm Xdebug
// Set breakpoint on the line below to inspect all injected dependencies
declare(strict_types=1);
namespace Mironsoft\Catalog\ViewModel;
use Magento\Framework\View\Element\Block\ArgumentInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Store\Model\StoreManagerInterface;
/**
* Product detail view model — demonstrates Xdebug inspection points.
*/
class ProductDetail implements ArgumentInterface
{
public function __construct(
private readonly ProductRepositoryInterface $productRepository,
private readonly StoreManagerInterface $storeManager,
) {
// Breakpoint here: inspect $this to verify injected dependencies
}
/**
* Get product by SKU — set breakpoint to inspect $product object graph.
*/
public function getProductBySku(string $sku): ?\Magento\Catalog\Api\Data\ProductInterface
{
try {
// Breakpoint here: Watch Expression '$sku' and $this->storeManager->getStore()->getId()
$product = $this->productRepository->get($sku);
return $product; // Inspect full product object with all extension attributes
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
// Breakpoint here: check $e->getMessage() in Evaluate window
return null;
}
}
}
6. Stack Traces und Call Stack in PhpStorm lesen
Der Call Stack im Debugger-Fenster zeigt die komplette Aufrufkette, die zur aktuellen Codezeile geführt hat. In Magento 2 kann dieser Stack 30 und mehr Ebenen tief sein, weil der Event-Observer-Mechanismus, die Plugin-Interception und das Dependency-Injection-Framework eigene Stack-Frames hinzufügen. PhpStorm zeigt jeden Frame mit Dateiname, Zeilennummer und Methodenname. Ein Klick auf einen Frame springt zu dieser Stelle im Code und zeigt die Variablen dieses Frames.
Besonders wertvoll beim Debugging von Magento 2 Plugins: Wenn ein Plugin (Interceptor) aufgerufen wird, sieht man im Call Stack sowohl den Original-Code als auch den generierten Interceptor-Code unter generated/code/. PhpStorm muss auch diesen Pfad in den Path Mappings kennen, damit man in den generierten Dateien Breakpoints setzen kann. Das ist relevant, wenn man verstehen will, in welcher Reihenfolge before-, around- und after-Plugins aufgerufen werden.
Wenn PhpStorm in einer Zeile hält, die nicht die erwartete Datei öffnet, liegt das oft an Path-Mapping-Problemen mit generierten Dateien. Die Lösung: unter Settings → PHP → Servers prüfen, ob /var/www/html/generated auf /home/mir/development/mironsoft/src/generated gemappt ist. Nach einem setup:di:compile ändert sich der Inhalt des generated/-Ordners – PhpStorm kann die neuen Dateien erst nach einem Reload der geänderten Dateien oder einem Projektneustart korrekt indexieren.
7. Container-Logs und Debugger kombinieren
Der Debugger allein zeigt nur, was im Code passiert. Container-Logs zeigen, was in der Infrastruktur passiert: welche SQL-Queries die Datenbank ausführt, welche Nginx-Requests ankommen, welche Redis-Operationen durchgeführt werden. Die Kombination aus Breakpoint und offenem Log-Tab im Services Tool Window gibt ein vollständiges Bild: Wann genau pausiert der Debugger, und welche Log-Einträge wurden zu diesem Zeitpunkt erzeugt?
Für Magento 2 ist die var/log/exception.log und die var/log/debug.log besonders relevant. Statt diese Logs im Terminal zu streamen, kann man sie im PhpStorm Log-Tab öffnen (Run → Open Log oder über das Services Tool Window). Mit einem offenen Debugger und einem offenen Log-Tab nebeneinander sieht man sofort, wenn eine Exception geloggt wird, bevor sie den Breakpoint erreicht – oder wenn ein Event-Observer eine Nebenwirkung erzeugt, die nicht direkt im Debugger sichtbar ist.
Eine fortgeschrittene Kombination: Xdebug-Tracing aktivieren (xdebug.mode=debug,trace) und den Trace mit dem Log-Tab kombinieren. Das Trace-File zeigt jeden Funktionsaufruf mit Zeitstempel und Ausführungszeit – so lassen sich Performance-Probleme lokalisieren, die beim normalen Debugging nicht sichtbar sind. PhpStorm kann Trace-Files direkt öffnen und in einer strukturierten Ansicht darstellen, in der man nach teuren Funktionsaufrufen filtern kann.
8. CLI-Debugging: Magento-Kommandos debuggen
Neben Web-Requests können auch CLI-Kommandos per Xdebug debuggt werden. Für Magento-Befehle wie bin/magento cache:flush, indexer:reindex oder benutzerdefinierte Konsolenbefehle ist das besonders nützlich. Die Konfiguration unterscheidet sich leicht: Statt eines Browser-Cookies wird die Umgebungsvariable XDEBUG_SESSION=PHPSTORM gesetzt, und xdebug.start_with_request=yes oder =trigger mit der gesetzten Umgebungsvariable aktiviert den Debugger für den CLI-Prozess.
In Mark Shustes Setup ist das Script bin/debug-cli bereits vorbereitet, das diese Umgebungsvariable setzt und den PHP-CLI-Prozess mit Xdebug startet. Statt bin/magento cache:flush ruft man dann bin/debug-cli bin/magento cache:flush auf – PhpStorm empfängt die Verbindung und pausiert beim ersten Breakpoint im Befehlscode. Das ist besonders wertvoll für das Debugging von DataPatch-, Schema-Patch- und Setup-Upgrade-Problemen, die im Webbrowser nicht zugänglich sind.
Ein häufiges Problem beim CLI-Debugging: Der Xdebug-Timeout ist zu kurz für langsame Magento-Befehle wie setup:di:compile. Die Direktive xdebug.connect_timeout_ms = 5000 gibt genug Zeit für den initialen Verbindungsaufbau. Außerdem sollte man max_execution_time = 0 im PHP-CLI-Context sicherstellen, damit langlaufende Befehle nicht durch ein Timeout unterbrochen werden, während man in einem Breakpoint wartet.
#!/bin/bash
# bin/debug-cli — Enable Xdebug for CLI commands in Docker container
# Usage: bin/debug-cli bin/magento indexer:reindex catalogsearch_fulltext
# Enable Xdebug for this single CLI execution
export XDEBUG_SESSION=PHPSTORM
export XDEBUG_CONFIG="client_host=host.docker.internal client_port=9003"
# Run the command inside the PHP container with Xdebug environment
docker compose exec \
-e XDEBUG_SESSION=PHPSTORM \
-e XDEBUG_CONFIG="client_host=host.docker.internal client_port=9003" \
-e PHP_IDE_CONFIG="serverName=mironsoft" \
php-fpm \
php "$@"
# PhpStorm must be listening for debug connections (Run → Start Listening)
# Set breakpoints in the command class before running this script
# Example: src/app/code/Mironsoft/Catalog/Console/Command/SyncProducts.php
9. var_dump vs. Xdebug: direkter Vergleich
Die Entscheidung zwischen var_dump() und Xdebug ist keine Frage des Stils, sondern der Effizienz. Beide haben ihren Platz, aber für komplexe Debugging-Szenarien – wie das Nachvollziehen eines Magento 2 Plugin-Stacks oder das Untersuchen eines Dependency-Injection-Fehlers – ist der Debugger deutlich mächtiger.
| Aspekt | var_dump / Logging | Xdebug + PhpStorm | Wann welches? |
|---|---|---|---|
| Einrichtungsaufwand | Kein Setup nötig | Einmalige Konfiguration | var_dump für Schnellcheck |
| Variablen-Tiefe | Begrenzt, schwer lesbar | Vollständig, navigierbar | Xdebug für komplexe Objekte |
| Call Stack | Nur debug_backtrace() | Vollständig, klickbar | Xdebug bei Plugin-Stacks |
| Performance-Impact | Minimal | Deutlich (mode=debug) | var_dump in Perf-Tests |
| Code-Änderung nötig | Ja (muss entfernt werden) | Nein | Xdebug für sauberen Code |
Die Praxis zeigt: Xdebug ist ideal für das strukturierte Debugging von Bugs in der Entwicklungsphase, bei dem man den Programmfluss verstehen muss. var_dump und Logging sind sinnvoll für schnelle Wertprüfungen während der Entwicklung und für Debugging in Environments, in denen kein Xdebug verfügbar ist. Das Ziel ist, var_dump-Aufrufe nicht in Commits zu lassen – PhpStorm warnt davor mit einer Inspektion und kann sie über einen Quick-Fix automatisch entfernen.
Mironsoft
Magento 2 Debugging und Entwicklungsinfrastruktur mit Docker und PhpStorm
Xdebug im Docker-Container einrichten lassen?
Wir konfigurieren Xdebug 3 für euer Docker-Magento-Setup, richten PhpStorm mit korrekten Path Mappings ein und schulen euer Team im professionellen Debuggen ohne var_dump-Raten.
Xdebug Setup
Xdebug 3 in Docker konfigurieren, PHP_IDE_CONFIG und Path Mappings einrichten
PhpStorm Config
Server-Konfiguration, Run-Configs und Debug-Workflows für das gesamte Team
Debug-Schulung
Breakpoints, Watch Expressions und CLI-Debugging in Magento 2 praktisch vermitteln
10. Zusammenfassung
Xdebug 3 in Docker-Container-Setups ist kein Hexenwerk, erfordert aber die korrekte Konfiguration von vier Stellen: der xdebug.ini im Container, der PHP_IDE_CONFIG-Umgebungsvariablen, der PhpStorm Server-Konfiguration mit Path Mappings, und dem Debug-Listening in der IDE. Sind diese vier Stellen korrekt konfiguriert, funktioniert das Debugging zuverlässig – mit echten Breakpoints, vollständiger Variablen-Inspektion, klickbarem Call Stack und Evaluate-Funktion für beliebige PHP-Ausdrücke.
Die Kombination aus Debugger und Container-Logs im Services Tool Window gibt das vollständige Bild: Was passiert im Code (Debugger), und was passiert in der Infrastruktur (Logs). CLI-Debugging über XDEBUG_SESSION-Umgebungsvariable macht auch Magento-Konsolenbefehle debuggbar. Das Ergebnis ist eine Debugging-Umgebung, die var_dump-Raten durch strukturierte Analyse ersetzt und die Fehlersuche von Stunden auf Minuten reduziert.
PhpStorm + Xdebug in Docker — Das Wichtigste auf einen Blick
Xdebug 3 Konfiguration
xdebug.mode=debug, client_host=host.docker.internal, client_port=9003, start_with_request=trigger. PHP_IDE_CONFIG=serverName=projektname setzen.
Path Mappings
Settings → PHP → Servers: Lokaler Pfad /src/ auf /var/www/html/ mappen. Auch generated/ mappen für Plugin-Interceptor-Debugging.
Debug-Session starten
Xdebug Helper Browser-Plugin setzt XDEBUG_SESSION-Cookie. PhpStorm muss auf Run → Start Listening for PHP Debug Connections stehen.
CLI-Debugging
XDEBUG_SESSION=PHPSTORM als Env-Variable setzen. bin/debug-cli Script für docker compose exec mit Xdebug-Variablen nutzen.