Profiling, Trace und Coverage fuer tiefe PHP-Analyse
Xdebug kann weit mehr, als eine Ausfuehrung an einer Zeile anzuhalten. Mit den Modi trace, profile, coverage und gcstats oeffnet Xdebug ein Analysefenster in den echten Laufzeitzustand eines PHP-Requests: Aufrufhierarchien mit Zeitstempeln, Cachegrind-Profile fuer Self-Time und Inclusive-Time, eine Coverage API fuer eigene Analysetools jenseits von PHPUnit und Garbage-Collection-Statistiken, die im Alltag komplett verborgen bleiben.
Inhaltsverzeichnis
- 1. Die Xdebug-Modi im Ueberblick
- 2. xdebug.mode und xdebug.start_with_request konfigurieren
- 3. Function Trace: Aufrufhierarchie mit Zeitstempeln
- 4. Code Coverage API jenseits von PHPUnit
- 5. Profiling mit Cachegrind-Output
- 6. GC Stats: Garbage Collection sichtbar machen
- 7. Selektive Aktivierung mit xdebug.trigger_value
- 8. Performance-Overhead der einzelnen Modi
- 9. Praxisbeispiel: Hot Path per Trace-Datei identifizieren
- 10. Zusammenfassung
- 11. FAQ
1. Die Xdebug-Modi im Ueberblick
Seit Xdebug 3 laeuft die Erweiterung nicht mehr als monolithischer Debugger, sondern als Sammlung einzeln aktivierbarer Modi. Jeder Modus schaltet genau eine Fahigkeit frei: develop liefert bessere var_dump()-Ausgaben, Stack Traces bei Fehlern und Warnungen bei Funktionsaufruf-Problemen. debug aktiviert das klassische DBGp-Protokoll fuer Breakpoint-Sessions in einer IDE, das ist der bekannte Teil von Xdebug. Vier weitere Modi bleiben im Alltag oft ungenutzt, obwohl sie fuer Performance-Analyse und Qualitaetssicherung mindestens genauso wertvoll sind: trace protokolliert jeden Funktionsaufruf in eine Datei, profile erzeugt Cachegrind-kompatible Profile, coverage stellt eine programmatische API fuer Code-Abdeckung bereit, und gcstats macht das Verhalten des Garbage Collectors sichtbar.
Die Modi lassen sich frei kombinieren, weil xdebug.mode eine kommagetrennte Liste akzeptiert. xdebug.mode=develop,trace aktiviert gleichzeitig bessere Fehlermeldungen und die Funktionsablaufverfolgung fuer denselben Request. In der Praxis kombiniert man selten mehr als zwei Modi gleichzeitig, weil sich sonst der Overhead addiert und die Ausgabedateien unhandlich gross werden. Wichtig zu verstehen: Xdebug selbst entscheidet nicht, welcher Modus fuer eine bestimmte Aufgabe der richtige ist, das bleibt eine bewusste Entscheidung des Entwicklers je nach Fragestellung, ob es um einen langsamen Request, eine unklare Testabdeckung oder eine vermutete Memory-Leak-Situation geht.
2. xdebug.mode und xdebug.start_with_request konfigurieren
Die Konfiguration erfolgt zentral ueber php.ini beziehungsweise eine dedizierte xdebug.ini im conf.d-Verzeichnis. Die zwei wichtigsten Direktiven sind xdebug.mode, welche Modi ueberhaupt geladen werden, und xdebug.start_with_request, ob Xdebug bei jedem Request automatisch aktiv wird oder nur nach einem expliziten Trigger. Der Unterschied ist entscheidend fuer den Betrieb: xdebug.start_with_request=yes aktiviert die konfigurierten Modi bei jedem einzelnen Request, was auf einer lokalen Entwicklungsumgebung unproblematisch ist, auf einem geteilten Staging-System aber schnell zu spuerbarer Verlangsamung fuer alle Nutzer fuehrt.
Der Wert trigger kehrt dieses Verhalten um: Xdebug bleibt inaktiv, bis ein Cookie, GET-Parameter oder Header mit dem Namen XDEBUG_TRIGGER im Request vorhanden ist. Dadurch laesst sich Xdebug auf einem Staging-Server dauerhaft geladen halten, ohne dass jeder Request automatisch den Overhead traegt. Nur wenn gezielt getriggert wird, schaltet sich der gewuenschte Modus fuer genau diesen einen Request scharf. Diese Trennung zwischen "geladen" und "aktiv" ist der Kern eines produktionsnahen Xdebug-Setups und wird in Abschnitt 7 vertieft.
; php.ini / conf.d/xdebug.ini
; Mehrere Modi kommagetrennt aktivierbar
xdebug.mode = develop,trace,profile
; yes = bei jedem Request aktiv, trigger = nur bei XDEBUG_TRIGGER
xdebug.start_with_request = trigger
; Zielverzeichnisse fuer Trace- und Profil-Dateien
xdebug.trace_output_dir = /var/log/xdebug/traces
xdebug.output_dir = /var/log/xdebug/profiles
; Menschenlesbares Trace-Format (0) statt binaer (1) oder HTML (2)
xdebug.trace_format = 0
; Cachegrind-Dateiname mit PID und Zeitstempel
xdebug.output_name = cachegrind.out.%p.%t
; Name des Trigger-Werts, den Cookie/GET/Header enthalten muessen
xdebug.trigger_value = STAGING_PROFILE
Auf Produktionssystemen sollte Xdebug in aller Regel gar nicht geladen sein, selbst mit trigger-Konfiguration bleibt ein minimaler Overhead durch den geladenen Extension-Code bestehen. Fuer Staging-Umgebungen ist die Kombination aus xdebug.mode mit mehreren Werten und xdebug.start_with_request=trigger jedoch der Standardweg, um Xdebug jederzeit verfuegbar zu halten, ohne dass er ungefragt in jeden Request eingreift.
3. Function Trace: Aufrufhierarchie mit Zeitstempeln
Der Modus trace protokolliert jeden einzelnen Funktions- und Methodenaufruf eines Requests in eine Datei im Verzeichnis, das xdebug.trace_output_dir festlegt. Jede Zeile enthaelt Verschachtelungstiefe, Zeitstempel relativ zum Requeststart, verbrauchten Speicher, Funktionsname sowie die uebergebenen Parameterwerte. Beim Verlassen einer Funktion protokolliert Xdebug zusaetzlich den Rueckgabewert, sofern xdebug.trace_format=0 gesetzt ist, das textbasierte und fuer Menschen lesbare Format. Diese Detailtiefe macht Traces zum praezisesten Werkzeug, um genau nachzuvollziehen, in welcher Reihenfolge und mit welchen Argumenten Code tatsaechlich durchlaufen wurde, ganz ohne eine einzige Breakpoint-Unterbrechung im laufenden Prozess.
Die Aufrufhierarchie zeigt sich durch die Einrueckung: Ein tiefer verschachtelter Aufruf erscheint mit mehr Fuehrungsleerzeichen, wodurch sich Rekursionstiefe und Verzweigungen auf einen Blick erkennen lassen. Die Zeitstempel pro Zeile sind kumulativ ab Requeststart, sodass die Differenz zwischen Eintritt und Austritt einer Funktion die tatsaechliche Laufzeit inklusive aller Unteraufrufe ergibt. Diese Information ist der eigentliche Mehrwert gegenueber einer Breakpoint-Session: Statt Schritt fuer Schritt manuell durch den Code zu klicken, liegt am Ende des Requests eine vollstaendige, durchsuchbare Aufzeichnung vor.
$ cat /var/log/xdebug/traces/trace.1234567.xt
TRACE START [2026-07-23 09:14:02.001234]
0.0002 393216 -> {main}() /app/public/index.php:0
0.0004 401920 -> App\Http\Kernel->handle() /app/public/index.php:12
0.0006 412160 -> App\Order\OrderRepository->findRecent() /app/src/Order/OrderRepository.php:28
>>> \$customerId = 4821
>>> \$limit = 25
0.0031 498304 -> PDO->prepare() /app/src/Order/OrderRepository.php:34
0.0089 512000 -> PDOStatement->execute() /app/src/Order/OrderRepository.php:35
0.0142 540672 -> App\Order\OrderRepository->findRecent() returns array(25 items)
0.0145 541200 -> App\Http\Kernel->handle() returns App\Http\Response
TRACE END [2026-07-23 09:14:02.019812]
An diesem Ausschnitt zeigt sich sofort, dass findRecent() allein 13,6 Millisekunden benoetigt (0.0142 minus 0.0006), waehrend die eigentliche SQL-Ausfuehrung ueber PDOStatement->execute() davon 5,3 Millisekunden beansprucht. Genau diese Art von Beobachtung, die eine Breakpoint-Session nur Schritt fuer Schritt und ohne Gesamtueberblick liefern wuerde, macht Function Trace zum bevorzugten Werkzeug fuer die erste Eingrenzung eines langsamen Requests.
4. Code Coverage API jenseits von PHPUnit
PHPUnit ist der bekannteste Konsument der Xdebug Coverage API, aber die Funktionen xdebug_start_code_coverage() und xdebug_get_code_coverage() lassen sich auch direkt im eigenen Code aufrufen, ganz ohne Testframework. Das ist nuetzlich, um beispielsweise nachzuvollziehen, welche Codezeilen ein bestimmter Produktionsrequest tatsaechlich durchlaeuft, welche Legacy-Funktionen ein einzelner CLI-Befehl beruehrt, oder um ein eigenes internes Analyse-Tool fuer tote Codezeilen zu bauen. Der Rueckgabewert von xdebug_get_code_coverage() ist ein Array, das pro Datei die Zeilennummern mit ihrem Status abbildet: eins fuer ausgefuehrt, minus zwei fuer nicht ausfuehrbar, minus eins fuer ausfuehrbar aber nicht erreicht.
Zusaetzlich zur einfachen Zeilenabdeckung unterstuetzt der Coverage-Modus zwei erweiterte Optionen. XDEBUG_CC_BRANCH_CHECK liefert Branch- und Path-Coverage, also welche Verzweigungen einer Bedingung tatsaechlich genommen wurden, nicht nur ob die Zeile ueberhaupt ausgefuehrt wurde. XDEBUG_CC_UNUSED markiert Zeilen, die niemals erreicht wurden, waehrend XDEBUG_CC_DEAD_CODE zusaetzlich unerreichbaren Code identifiziert, etwa nach einem return-Statement. Diese Flags werden als Bitmaske dem zweiten Parameter von xdebug_start_code_coverage() uebergeben.
<?php
declare(strict_types=1);
// Programmatic coverage collection without a test framework
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_BRANCH_CHECK);
require __DIR__ . '/bootstrap.php';
$app = new Application();
$app->handle($_SERVER);
$coverage = xdebug_get_code_coverage();
xdebug_stop_code_coverage();
$report = [];
foreach ($coverage as $file => $lines) {
$executed = array_filter($lines, static fn (int $status): bool => $status === 1);
$unreached = array_filter($lines, static fn (int $status): bool => $status === -1);
$report[$file] = [
'executed_lines' => count($executed),
'unreached_lines' => count($unreached),
];
}
// Persist as JSON for a custom analysis dashboard, independent of PHPUnit
file_put_contents(
'/var/log/coverage/request-' . uniqid() . '.json',
json_encode($report, JSON_PRETTY_PRINT)
);
Diese Technik eignet sich besonders fuer produktionsnahe Analysen: Ein Middleware-Hook startet die Coverage-Sammlung am Requestbeginn und schreibt am Requestende einen kompakten Report weg, aggregiert ueber viele Requests hinweg laesst sich so erkennen, welcher Anteil einer grossen Codebasis im realen Betrieb ueberhaupt jemals ausgefuehrt wird. Fuer eine solche Dauerbeobachtung sollte der Coverage-Modus jedoch nur auf einem einzelnen Canary-Server aktiv sein, da auch dieser Modus messbaren Overhead erzeugt.
5. Profiling mit Cachegrind-Output
Der Modus profile schreibt fuer jeden Request eine Datei im Cachegrind-Format in das durch xdebug.output_dir festgelegte Verzeichnis. Dieses Format wurde urspruenglich von Valgrind fuer die C-Welt entwickelt und wird von einer ganzen Reihe von Analyse-Werkzeugen verstanden, ohne dass eine IDE beteiligt sein muss. Auf einem Linux-Desktop oeffnet kcachegrind (beziehungsweise die plattformunabhaengige Variante qcachegrind) die Datei grafisch mit Aufrufgraphen und sortierbaren Funktionslisten. Wer keinen Desktop mit grafischer Oberflaeche zur Verfuegung hat, etwa auf einem Remote-Server, nutzt callgrind_annotate aus dem Valgrind-Paket direkt auf der Kommandozeile fuer eine textbasierte Auswertung.
Der zentrale Interpretationsschluessel jedes Cachegrind-Profils ist die Unterscheidung zwischen Self-Time und Inclusive-Time. Self-Time misst ausschliesslich die Zeit, die im Code der Funktion selbst verbracht wurde, ohne Zeit in aufgerufenen Unterfunktionen. Inclusive-Time summiert die Zeit der Funktion und aller von ihr aufgerufenen Funktionen zusammen. Eine Funktion mit hoher Inclusive-Time aber niedriger Self-Time ist meist nur ein duenner Wrapper, der viel Zeit an tiefer liegende Aufrufe weiterreicht, waehrend eine Funktion mit hoher Self-Time selbst der eigentliche Flaschenhals ist, den es zu optimieren gilt.
$ ls /var/log/xdebug/profiles/
cachegrind.out.48213.1753253642
$ callgrind_annotate --auto=yes /var/log/xdebug/profiles/cachegrind.out.48213.1753253642 | head -20
--------------------------------------------------------------------------------
Profile data file 'cachegrind.out.48213.1753253642' (creator: xdebug)
--------------------------------------------------------------------------------
Summary: 184532910
Ir file:function
184532910 PROGRAM TOTALS
ms Self (ms) Inclusive (ms) Calls file:function
- 2.10 142.30 1 index.php:App\Http\Kernel->handle
- 0.85 118.40 1 OrderRepository.php:findRecent
- 104.90 104.90 18420 PriceCalculator.php:calculateTax (self time hot path)
- 8.60 12.30 25 OrderRepository.php:hydrate
In diesem Beispiel faellt calculateTax() sofort auf: 104,9 Millisekunden Self-Time bei 18.420 Aufrufen, praktisch identisch mit der Inclusive-Time, das heisst die Funktion verbringt ihre gesamte Zeit im eigenen Code und ruft nichts Nennenswertes weiter auf. Das ist der klassische Fingerabdruck einer Funktion, die in einer Schleife unnoetig oft aufgerufen wird, etwa weil ein Ergebnis nicht zwischengespeichert wird. Ohne Cachegrind-Profil waere diese Erkenntnis aus reinem Quellcode-Lesen kaum ableitbar.
6. GC Stats: Garbage Collection sichtbar machen
Der Modus gcstats ist der am wenigsten bekannte der Xdebug-Modi, weil PHPs zyklischer Garbage Collector im Alltag selten Beachtung findet, solange kein Speicherproblem auftritt. Aktiviert man xdebug.mode=gcstats, schreibt Xdebug am Ende jedes Requests eine Datei, die protokolliert, wie oft der Garbage Collector Zyklen-Erkennung durchgefuehrt hat, wie viele Root-Buffer-Eintraege dabei verarbeitet wurden und wie viele Speicherzyklen tatsaechlich als unerreichbar erkannt und freigegeben wurden.
Diese Zahlen werden relevant, wenn ein Request unerwartet viel Speicher verbraucht oder auffaellig lange braucht, obwohl das Trace-Profil keinen offensichtlichen Hot Path zeigt. Ein hoher Wert an erkannten Zyklen deutet auf viele zirkulaere Referenzen hin, etwa durch Objekte, die sich gegenseitig referenzieren, klassischerweise bei Observer-Mustern, Doctrine-Entities mit bidirektionalen Beziehungen oder Event-Listener-Strukturen ohne Weak References. Der GC muss diese Zyklen aktiv aufloesen, was CPU-Zeit kostet, die im reinen Trace nicht als eigener Funktionsaufruf erscheint, sondern sich als schwer zuzuordnende Verzoegerung zwischen zwei Zeilen zeigt.
7. Selektive Aktivierung mit xdebug.trigger_value
Auf einer Staging-Umgebung mit mehreren gleichzeitigen Nutzern waere es unpraktikabel, Xdebug fuer jeden Request scharf zu schalten. Die Direktive xdebug.trigger_value loest dieses Problem, indem sie festlegt, welchen konkreten Wert das Cookie, der GET-Parameter oder der Header XDEBUG_TRIGGER tragen muss, damit Xdebug ueberhaupt aktiv wird. Ist der Wert leer, akzeptiert Xdebug jeden beliebigen nicht-leeren Trigger, was auf einem geteilten System ein Sicherheitsrisiko darstellt, da jeder Nutzer mit Kenntnis des Headernamens beliebige Requests profilieren koennte. Mit einem konkreten, projektspezifischen Wert wie STAGING_PROFILE wird der Trigger faktisch zu einem einfachen Zugangsschluessel.
Fuer den taeglichen Gebrauch reicht ein einzelner Header oder ein Cookie im Browser, ueber eine Browser-Extension oder manuell per curl gesetzt. Da nur der einzelne markierte Request den gewaehlten Modus aktiviert, bleibt der restliche Traffic auf dem Staging-System vollstaendig unbeeintraechtigt, selbst wenn xdebug.mode=develop,trace,profile dauerhaft in der Konfiguration hinterlegt ist. Genau diese Kombination aus geladenen Modi plus gezieltem Trigger ist der professionelle Mittelweg zwischen "Xdebug ist nie verfuegbar" und "Xdebug bremst jeden Request aus".
# Trace and profile mode triggered for exactly this one request via header
$ curl -H "X-Xdebug-Trigger: STAGING_PROFILE" \
-H "Cookie: XDEBUG_TRIGGER=STAGING_PROFILE" \
https://staging.example.com/checkout/cart
# Alternative: GET parameter, useful for quick ad-hoc checks in a browser tab
$ curl "https://staging.example.com/checkout/cart?XDEBUG_TRIGGER=STAGING_PROFILE"
# Resulting files appear only for this single request
$ ls -la /var/log/xdebug/traces/ /var/log/xdebug/profiles/
trace.stagingweb01.1753253642.xt
cachegrind.out.stagingweb01.1753253642
8. Performance-Overhead der einzelnen Modi
Nicht alle Xdebug-Modi kosten gleich viel Laufzeit. develop und debug ohne aktive Session bleiben nahezu kostenlos, weil sie nur bei tatsaechlichen Fehlern beziehungsweise bei einer verbundenen IDE-Session ueberhaupt Zusatzarbeit leisten. gcstats ist ebenfalls guenstig, da nur wenige Zaehler am Requestende ausgewertet werden. coverage liegt im mittleren Bereich, abhaengig davon, ob Branch-Check aktiviert ist. Die beiden teuersten Modi sind trace und profile: Beide instrumentieren jeden einzelnen Funktionsaufruf im Prozess, schreiben pro Aufruf mindestens eine Zeile in eine Datei oder aktualisieren einen internen Zaehlerbaum, und koennen die Requestdauer je nach Codebasis auf das Drei- bis Zehnfache verlangsamen.
Aus diesem Grund gehoeren trace und profile strikt auf Staging-Systeme oder in lokale Entwicklungsumgebungen, niemals dauerhaft auf Produktionsserver. Selbst mit xdebug.start_with_request=trigger bleibt ein einzelner getriggerter Produktionsrequest ein reales Risiko, wenn er zufaellig einen ressourcenintensiven Endpunkt trifft und dadurch andere Requests auf demselben Worker verzoegert. Die saubere Isolation gelingt entweder durch einen dedizierten Canary-Host, der Traffic gespiegelt bekommt, oder durch eine lokale Kopie der Produktionsdaten in einer Staging-Umgebung, auf der Trace- und Profil-Sessions ohne Risiko fuer echte Nutzer gefahren werden koennen.
| Modus | Zweck | Performance-Overhead | Typischer Einsatzort |
|---|---|---|---|
trace |
Aufrufhierarchie mit Parametern, Rueckgaben, Zeitstempeln | Sehr hoch | Staging, lokal |
profile |
Cachegrind-Profile fuer Self-/Inclusive-Time | Sehr hoch | Staging, lokal |
coverage |
Zeilen-, Branch- und Path-Coverage programmatisch | Mittel | CI, Staging (Canary) |
gcstats |
Garbage-Collection-Zyklen und Speicherfreigabe | Gering | Staging, gezielt |
debug |
Interaktive Breakpoint-Session via DBGp | Mittel (nur bei aktiver Session) | Lokal |
9. Praxisbeispiel: Hot Path per Trace-Datei identifizieren
Ein konkretes Szenario verdeutlicht das Zusammenspiel der Modi: Ein Reporting-Endpunkt braucht auf Staging ploetzlich 4 Sekunden statt der ueblichen 300 Millisekunden, nachdem eine rekursive Funktion zur Berechnung verschachtelter Kategoriebaeume hinzugefuegt wurde. Der erste Schritt ist, xdebug.mode=trace per Trigger fuer genau diesen einen Request zu aktivieren und die entstandene .xt-Datei zu oeffnen. Bereits ein kurzer Blick auf die Einrueckungstiefe zeigt eine auffaellig tiefe, sich wiederholende Verschachtelung derselben Funktion buildCategoryTree(), was auf unerwartet hohe Rekursionstiefe hindeutet.
Der zweite Schritt ist eine gezielte Textsuche in der Trace-Datei nach dem Funktionsnamen: Zaehlt man die Vorkommen von buildCategoryTree(), zeigt sich schnell, ob die Funktion zehnmal oder zehntausendmal aufgerufen wurde. Im vorliegenden Fall waren es ueber 40.000 Aufrufe fuer einen Baum mit lediglich 200 Knoten, ein klares Indiz fuer eine fehlende Memoisierung: Derselbe Teilbaum wurde wiederholt neu berechnet, statt ein bereits berechnetes Ergebnis wiederzuverwenden. Die Parameterwerte in der Trace-Datei bestaetigten das, dieselbe Knoten-ID tauchte mehrfach mit identischen Argumenten auf.
Der dritte Schritt wechselt zu xdebug.mode=profile, um die Selbstzeit exakt zu quantifizieren: Das Cachegrind-Profil zeigte buildCategoryTree() mit der hoechsten Inclusive-Time im gesamten Request, aber vergleichsweise niedriger Self-Time, ein klares Zeichen dafuer, dass nicht die Funktion selbst ineffizient ist, sondern die schiere Aufrufzahl das Problem ist. Nach Einbau eines einfachen Ergebnis-Caches innerhalb des Requests sank die Aufrufzahl von 40.000 auf rund 200, die Requestzeit fiel auf 280 Millisekunden. Ohne Trace-Datei waere die Aufrufzahl kaum messbar gewesen, ohne Cachegrind-Profil waere unklar geblieben, ob die Funktion selbst oder ihre Aufrufhaeufigkeit das eigentliche Problem darstellt.
10. Zusammenfassung
Xdebug ist weit mehr als ein Breakpoint-Debugger fuer die IDE. Die Modi trace, profile, coverage und gcstats erschliessen vier vollstaendig unterschiedliche Sichten auf denselben Requestverlauf: die exakte Aufrufhierarchie mit Zeitstempeln, ein Cachegrind-Profil fuer Self- und Inclusive-Time, eine programmatische Coverage API fuer eigene Analyse-Tools und Garbage-Collection-Statistiken fuer versteckte Speicherprobleme. Jeder dieser Modi beantwortet eine andere Frage, und keiner ersetzt die klassische Breakpoint-Session vollstaendig, sie ergaenzen sich gegenseitig je nach Symptom.
Der professionelle Umgang mit Xdebug bedeutet, die Modi bewusst und gezielt einzusetzen: konfiguriert ueber xdebug.mode in der php.ini, kontrolliert ueber xdebug.start_with_request=trigger und xdebug.trigger_value, ausschliesslich auf Staging-Systemen oder lokal, niemals dauerhaft in Produktion. Wer diese Disziplin einhaelt, gewinnt mit Xdebug ein Analysewerkzeug, das weit ueber das Anhalten an einer einzelnen Zeile hinausgeht und tiefgreifende Performance- und Qualitaetsfragen mit konkreten, reproduzierbaren Daten beantwortet.
Xdebug jenseits von Breakpoints: Das Wichtigste auf einen Blick
Function Trace
xdebug.mode=trace protokolliert jeden Funktionsaufruf mit Parametern, Rueckgabewerten und Zeitstempeln in eine Datei, ganz ohne Breakpoints.
Cachegrind-Profiling
xdebug.mode=profile erzeugt Profile fuer kcachegrind, qcachegrind oder callgrind_annotate, mit klarer Trennung von Self- und Inclusive-Time.
Coverage API
xdebug_start_code_coverage() und xdebug_get_code_coverage() ermoeglichen eigene Analyse-Tools jenseits von PHPUnit.
Selektive Aktivierung
xdebug.start_with_request=trigger plus xdebug.trigger_value haelt Staging-Systeme fuer alle anderen Requests unbelastet.
11. FAQ: Xdebug jenseits von Breakpoints
1Unterschied zwischen develop und debug?
2Mehrere Modi gleichzeitig aktivieren?
3Was macht xdebug.start_with_request=trigger?
4Wie liest man eine Trace-Datei?
5Coverage API ohne PHPUnit nutzbar?
6Cachegrind-Datei ohne IDE analysieren?
7Self-Time vs. Inclusive-Time?
8Was zeigt gcstats an?
9Selektive Aktivierung in Staging?
10Warum sind trace und profile so langsam?
Mironsoft
PHP-Performance-Analyse, Profiling und tiefgreifendes Debugging
PHP-Anwendungen, die unter Last analysierbar bleiben?
Wir richten Xdebug-Trace, Cachegrind-Profiling und die Coverage API sauber in Staging-Umgebungen ein, identifizieren Hot Paths und liefern konkrete, messbare Optimierungen fuer eure PHP-Codebasis.
Performance-Audit
Trace- und Cachegrind-Analyse bestehender Hot Paths mit konkreten Zahlen
Staging-Setup
Xdebug-Modi und Trigger-Konfiguration ohne Risiko fuer Produktionstraffic
Coverage-Tooling
Eigene Analyse-Tools auf Basis der Xdebug Coverage API jenseits von PHPUnit