Xdebug lt. claude
This commit is contained in:
@@ -0,0 +1,579 @@
|
|||||||
|
# Xdebug – Installation, Konfiguration, Nutzung
|
||||||
|
|
||||||
|
Stand: Xdebug 3.x (Modus-Konfiguration ab Xdebug 3, Port **9003**)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Vorab: Versionsmatrix
|
||||||
|
|
||||||
|
| PHP | Xdebug | Konfigurationsstil |
|
||||||
|
|---|---|---|
|
||||||
|
| 7.0 – 7.1 | 2.9.x | `xdebug.remote_*`, Port 9000 |
|
||||||
|
| 7.2 – 7.4 | 3.1.x | `xdebug.mode`, Port 9003 |
|
||||||
|
| 8.0 – 8.2 | 3.2.x | `xdebug.mode`, Port 9003 |
|
||||||
|
| 8.3+ | 3.3+ / 3.5+ | `xdebug.mode`, Port 9003 |
|
||||||
|
|
||||||
|
> Xdebug 3.5 setzt mindestens PHP 8.3 voraus. Bei älterem PHP die Version explizit pinnen:
|
||||||
|
> `pecl install xdebug-3.2.2`
|
||||||
|
|
||||||
|
Verzeichnisnamen wie `no-debug-non-zts-20220829` kodieren die PHP-API-Version:
|
||||||
|
`20220829` = PHP 8.2, `20230831` = PHP 8.3, `20240924` = PHP 8.4.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Installation unter XAMPP (macOS)
|
||||||
|
|
||||||
|
Xdebug wird für macOS **nicht** vorkompiliert ausgeliefert – es muss gebaut werden.
|
||||||
|
|
||||||
|
### 1.1 Vorbereitung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xcode-select --install # Compiler / Command Line Tools
|
||||||
|
brew install autoconf # phpize benötigt autoconf
|
||||||
|
```
|
||||||
|
|
||||||
|
Auf Apple Silicon zusätzlich:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
softwareupdate --install-rosetta --agree-to-license
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 Architektur-Falle (Apple Silicon)
|
||||||
|
|
||||||
|
XAMPP für macOS ist **x86_64** und läuft unter Rosetta 2. Ein nativer Build auf einem
|
||||||
|
M-Mac erzeugt eine arm64-`.so`, die PHP nicht laden kann:
|
||||||
|
|
||||||
|
```
|
||||||
|
dlopen(...) (mach-o file, but is an incompatible architecture
|
||||||
|
(have 'arm64', need 'x86_64'))
|
||||||
|
```
|
||||||
|
|
||||||
|
`arch -x86_64` **vor** `pecl` reicht nicht – `pecl` ist ein PHP-Skript, dessen
|
||||||
|
Kindprozesse (`phpize`, `configure`, `clang`) die Rosetta-Umgebung nicht zuverlässig
|
||||||
|
erben. Deshalb eine komplette x86_64-Shell öffnen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
arch -x86_64 /bin/zsh
|
||||||
|
arch # muss "i386" ausgeben
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 Build via pecl
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Alte Reste entfernen, sonst wird der falsche Build wiederverwendet
|
||||||
|
sudo rm -f /Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-*/xdebug.so
|
||||||
|
rm -rf /tmp/pear
|
||||||
|
|
||||||
|
# PEAR-Registry abmelden (sonst: "already installed ... install failed")
|
||||||
|
sudo /Applications/XAMPP/xamppfiles/bin/pecl uninstall xdebug
|
||||||
|
|
||||||
|
# Build (in der Rosetta-Shell!)
|
||||||
|
sudo CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" CXXFLAGS="-arch x86_64" \
|
||||||
|
/Applications/XAMPP/xamppfiles/bin/pecl install xdebug-3.2.2
|
||||||
|
```
|
||||||
|
|
||||||
|
`pecl` gibt am Ende die Zeile `Installing '/Applications/XAMPP/.../xdebug.so'` aus –
|
||||||
|
**das** ist der Pfad für die `php.ini`.
|
||||||
|
|
||||||
|
### 1.4 Ergebnis prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
file /Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so
|
||||||
|
# muss "x86_64" enthalten
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.5 Manueller Build (falls pecl scheitert)
|
||||||
|
|
||||||
|
Gibt mehr Kontrolle, weil jeder Schritt einzeln sichtbar ist:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /tmp && curl -O https://xdebug.org/files/xdebug-3.2.2.tgz
|
||||||
|
tar -xzf xdebug-3.2.2.tgz && cd xdebug-3.2.2
|
||||||
|
|
||||||
|
/Applications/XAMPP/xamppfiles/bin/phpize
|
||||||
|
./configure --with-php-config=/Applications/XAMPP/xamppfiles/bin/php-config \
|
||||||
|
CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64"
|
||||||
|
make
|
||||||
|
file modules/xdebug.so # VOR dem Kopieren prüfen
|
||||||
|
sudo cp modules/xdebug.so \
|
||||||
|
/Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20220829/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.6 XAMPP-VM (macOS)
|
||||||
|
|
||||||
|
Bei dieser Variante läuft der Stack in einer Linux-VM; die Mac-Pfade sind nur Mounts.
|
||||||
|
Ein Build auf dem Host bringt nichts. Terminal in der VM öffnen (XAMPP-Fenster →
|
||||||
|
*General* / *Volumes*) und dort nach Linux-Verfahren vorgehen.
|
||||||
|
|
||||||
|
### 1.7 Alternative ohne Compile-Schmerz
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install php # natives arm64-PHP
|
||||||
|
pecl install xdebug # läuft ohne Rosetta durch
|
||||||
|
php -S localhost:8000 # eingebauter Server statt Apache
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Installation unter XAMPP (Windows)
|
||||||
|
|
||||||
|
Deutlich einfacher – es gibt fertige DLLs.
|
||||||
|
|
||||||
|
### 2.1 Passende DLL ermitteln
|
||||||
|
|
||||||
|
XAMPP kompiliert PHP als **Thread Safe** (Apache mit mod_php), also wird eine TS-DLL
|
||||||
|
benötigt. Statt zu raten, den Xdebug-Wizard nutzen:
|
||||||
|
|
||||||
|
**https://xdebug.org/wizard**
|
||||||
|
|
||||||
|
1. `phpinfo()`-Ausgabe erzeugen – im Browser (`http://localhost/info.php`) oder per
|
||||||
|
`C:\xampp\php\php.exe -i > info.txt`
|
||||||
|
2. **Kompletten** Output kopieren (Strg+A / Strg+C), nicht nur die sichtbare Tabelle
|
||||||
|
3. Ins Textfeld einfügen → *Analyse my phpinfo() output*
|
||||||
|
4. Der Wizard nennt exakt die passende Datei, z. B.
|
||||||
|
`php_xdebug-3.4.x-8.2-vs16-x86_64.dll`
|
||||||
|
|
||||||
|
> Alternativ manuell unter https://xdebug.org/download – dann Thread Safety und
|
||||||
|
> VS/VC-Compilerversion selbst aus `phpinfo()` ablesen.
|
||||||
|
|
||||||
|
Nach dem Test: **`info.php` wieder löschen.**
|
||||||
|
|
||||||
|
### 2.2 Installieren
|
||||||
|
|
||||||
|
DLL kopieren nach `C:\xampp\php\ext\php_xdebug.dll`, dann in `C:\xampp\php\php.ini`
|
||||||
|
(ganz unten steht bereits ein auskommentierter `[XDebug]`-Block):
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[XDebug]
|
||||||
|
zend_extension = xdebug
|
||||||
|
xdebug.mode = develop,debug
|
||||||
|
xdebug.start_with_request = trigger
|
||||||
|
xdebug.client_port = 9003
|
||||||
|
xdebug.client_host = 127.0.0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 Prüfen
|
||||||
|
|
||||||
|
Apache über das Control Panel **Stop/Start** (nicht nur „Config"), dann:
|
||||||
|
|
||||||
|
```
|
||||||
|
C:\xampp\php\php.exe -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Die Ausgabe muss `with Xdebug v3.x.x` enthalten.
|
||||||
|
|
||||||
|
### 2.4 Häufige Fehler
|
||||||
|
|
||||||
|
| Symptom | Ursache |
|
||||||
|
|---|---|
|
||||||
|
| Extension wird stillschweigend ignoriert | `extension=` statt `zend_extension=` |
|
||||||
|
| Änderung wirkt nicht | falsche `php.ini` bearbeitet |
|
||||||
|
| Architekturfehler | x86 statt x64 oder NTS statt TS |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Installation unter Debian
|
||||||
|
|
||||||
|
Der bequemste Fall – Paketverwaltung erledigt alles.
|
||||||
|
|
||||||
|
### 3.1 Über apt
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install php-xdebug
|
||||||
|
# oder versionsspezifisch, z. B. bei Sury-Repository:
|
||||||
|
sudo apt install php8.4-xdebug
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Über pecl (wenn kein Paket verfügbar)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install php-pear php-dev autoconf
|
||||||
|
sudo pecl install xdebug
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 Konfiguration – hier gilt `conf.d`
|
||||||
|
|
||||||
|
Debian nutzt ein Scan-Verzeichnis. **Nicht** die zentrale `php.ini` anfassen, sondern
|
||||||
|
eine eigene Datei anlegen:
|
||||||
|
|
||||||
|
```
|
||||||
|
/etc/php/8.4/apache2/conf.d/99-xdebug-local.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
```ini
|
||||||
|
xdebug.mode = develop,debug
|
||||||
|
xdebug.start_with_request = trigger
|
||||||
|
xdebug.client_port = 9003
|
||||||
|
xdebug.discover_client_host = 1
|
||||||
|
xdebug.var_display_max_depth = 10
|
||||||
|
xdebug.var_display_max_data = 1024
|
||||||
|
xdebug.var_display_max_children = 256
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warum `99-`?** Die Dateien werden alphabetisch geladen, die letzte gewinnt. Xdebug
|
||||||
|
bringt typischerweise `20-xdebug.ini` mit – `99-` läuft danach und überschreibt.
|
||||||
|
Außerdem überlebt die eigene Datei ein `apt upgrade`, während Änderungen an der
|
||||||
|
zentralen `php.ini` einen Konfliktdialog auslösen.
|
||||||
|
|
||||||
|
### 3.4 SAPI-Trennung beachten
|
||||||
|
|
||||||
|
Debian hat getrennte Bäume:
|
||||||
|
|
||||||
|
```
|
||||||
|
/etc/php/8.4/apache2/conf.d/
|
||||||
|
/etc/php/8.4/fpm/conf.d/
|
||||||
|
/etc/php/8.4/cli/conf.d/
|
||||||
|
```
|
||||||
|
|
||||||
|
Eine Änderung in `cli/` wirkt **nicht** auf den Webserver. Meist sind es Symlinks nach
|
||||||
|
`/etc/php/8.4/mods-available/` – dort anlegen und mit `phpenmod` aktivieren, dann gilt
|
||||||
|
sie für beide.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl restart apache2
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Wo wird was eingetragen?
|
||||||
|
|
||||||
|
### 4.1 Die entscheidende Frage zuerst
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -i | grep -E "Loaded Configuration|Scan this dir"
|
||||||
|
```
|
||||||
|
|
||||||
|
| Ergebnis bei *Scan this dir* | Vorgehen |
|
||||||
|
|---|---|
|
||||||
|
| ein Verzeichnispfad | eigene Datei mit hoher Nummer, z. B. `99-xdebug-local.ini` |
|
||||||
|
| `(none)` | direkt in die `php.ini` (Loaded Configuration File) |
|
||||||
|
|
||||||
|
**XAMPP → immer `php.ini`** (Windows, macOS, Linux). XAMPP liefert bewusst eine
|
||||||
|
einzige, selbst verwaltete Datei ohne `conf.d`.
|
||||||
|
Ausnahme: **XAMPP-VM auf macOS** – innen läuft ein Debian, dort ggf. doch `conf.d`.
|
||||||
|
Also in der VM einmal `php -i | grep "Scan this dir"` prüfen.
|
||||||
|
|
||||||
|
**Debian / RHEL / Sury / Docker-Images → `conf.d` mit `99-…`**
|
||||||
|
|
||||||
|
> CLI und Browser können unterschiedliche INIs laden. Was Apache tatsächlich nutzt,
|
||||||
|
> zeigt nur `phpinfo()` im Browser.
|
||||||
|
|
||||||
|
### 4.2 Referenz-Konfiguration
|
||||||
|
|
||||||
|
```ini
|
||||||
|
zend_extension = xdebug.so ; NICHT "extension="!
|
||||||
|
|
||||||
|
; Was Xdebug tut
|
||||||
|
xdebug.mode = develop,debug ; develop = schöneres var_dump + Stack-Traces
|
||||||
|
; debug = Breakpoints
|
||||||
|
; trace = Aufrufprotokoll in Datei
|
||||||
|
; profile = Performance-Analyse
|
||||||
|
|
||||||
|
; Wann Xdebug aktiv wird
|
||||||
|
xdebug.start_with_request = trigger ; nur bei ?XDEBUG_TRIGGER=1 – hält Overhead klein
|
||||||
|
|
||||||
|
; Verbindung zur IDE
|
||||||
|
xdebug.client_port = 9003
|
||||||
|
xdebug.client_host = 127.0.0.1
|
||||||
|
xdebug.discover_client_host = 1 ; praktisch bei Remote / Lima / Docker
|
||||||
|
|
||||||
|
; Anzeige-Limits (Defaults sind zu knapp!)
|
||||||
|
xdebug.var_display_max_depth = 10 ; Default 3
|
||||||
|
xdebug.var_display_max_children = 256 ; Default 128
|
||||||
|
xdebug.var_display_max_data = 1024 ; Default 512
|
||||||
|
```
|
||||||
|
|
||||||
|
Die drei Anzeige-Limits sind der Grund, warum `var_dump` oft `...` statt der
|
||||||
|
eigentlichen Daten zeigt.
|
||||||
|
|
||||||
|
### 4.3 Ohne Dateisystemzugriff
|
||||||
|
|
||||||
|
**`.htaccess`** (nur bei mod_php, nicht FPM; erfordert `AllowOverride Options`):
|
||||||
|
|
||||||
|
```apache
|
||||||
|
php_value xdebug.var_display_max_depth 10
|
||||||
|
php_flag xdebug.collect_return 1
|
||||||
|
```
|
||||||
|
|
||||||
|
**Im Skript** – funktioniert nur für `PHP_INI_ALL`-Direktiven:
|
||||||
|
|
||||||
|
```php
|
||||||
|
ini_set('xdebug.var_display_max_depth', '10');
|
||||||
|
ini_set('xdebug.var_display_max_data', '1024');
|
||||||
|
```
|
||||||
|
|
||||||
|
Zwei Fallstricke:
|
||||||
|
- Die Werte wirken erst auf `var_dump`-Aufrufe **nach** dem `ini_set()`
|
||||||
|
- Gilt nur für den einen Request (nicht für separate Ajax-/Cron-Skripte)
|
||||||
|
|
||||||
|
`xdebug.mode` ist `PHP_INI_SYSTEM` und lässt sich zur Laufzeit **nicht** setzen.
|
||||||
|
|
||||||
|
**Auf der CLI ganz ohne Datei:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -d xdebug.mode=develop,trace -d xdebug.start_with_request=yes script.php
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 Prüfen, ob es angekommen ist
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -v # "with Xdebug v3.x.x"
|
||||||
|
php -i | grep xdebug.mode # CLI
|
||||||
|
```
|
||||||
|
|
||||||
|
Im Browser: `phpinfo()` aufrufen, dort muss ein eigener Xdebug-Abschnitt erscheinen.
|
||||||
|
Oder `xdebug_info()` – zeigt Konfiguration und aktuellen Zustand kompakt an.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Debuggen – wo sieht man was?
|
||||||
|
|
||||||
|
Drei Ebenen, unabhängig voneinander nutzbar.
|
||||||
|
|
||||||
|
### 5.1 Ebene 1: `develop` – ohne jede Zusatzsoftware
|
||||||
|
|
||||||
|
Aktiv allein durch `xdebug.mode = develop`:
|
||||||
|
|
||||||
|
- `var_dump()` farbig, eingerückt, mit Datei und Zeile – **kein `<pre>` mehr nötig**
|
||||||
|
- lesbare Stack-Traces bei jedem Fehler und jeder Warnung
|
||||||
|
- `xdebug_info()` als Konfigurations-Übersicht im Browser
|
||||||
|
|
||||||
|
**Ausgabeort:** direkt im Browser bzw. auf STDOUT der CLI.
|
||||||
|
|
||||||
|
Nützliche Funktionen:
|
||||||
|
|
||||||
|
```php
|
||||||
|
xdebug_break(); // Breakpoint aus dem Code heraus
|
||||||
|
var_dump(xdebug_get_function_stack()); // Wer hat mich aufgerufen?
|
||||||
|
echo xdebug_call_line();
|
||||||
|
error_log(xdebug_print_function_stack()); // Stack ins Log
|
||||||
|
```
|
||||||
|
|
||||||
|
Zur Erinnerung – ohne Xdebug hilft `<pre>`, weil `var_dump` Plaintext ausgibt und der
|
||||||
|
Browser Whitespace kollabiert:
|
||||||
|
|
||||||
|
```php
|
||||||
|
function dbg(...$vars): void {
|
||||||
|
ini_set('xdebug.var_display_max_depth', '10');
|
||||||
|
ini_set('xdebug.var_display_max_data', '1024');
|
||||||
|
echo '<pre style="text-align:left">';
|
||||||
|
var_dump(...$vars);
|
||||||
|
echo '</pre>';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`var_dump()` ist variadisch – mehrere Werte auf einmal sind erlaubt. Praktischer Trick
|
||||||
|
zur Orientierung: `var_dump(__LINE__, $row);`
|
||||||
|
|
||||||
|
### 5.2 Ebene 2: `trace` – Step-Debugging im Nachhinein
|
||||||
|
|
||||||
|
Wenn keine IDE zur Verfügung steht, oft der stärkste Hebel.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
xdebug.mode = develop,trace
|
||||||
|
xdebug.start_with_request = trigger
|
||||||
|
xdebug.output_dir = /tmp
|
||||||
|
xdebug.trace_format = 0
|
||||||
|
xdebug.collect_params = 4 ; volle Argumentwerte
|
||||||
|
xdebug.collect_return = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Ein Request mit `?XDEBUG_TRIGGER=1` schreibt `/tmp/trace.*.xt` – eine vollständige,
|
||||||
|
eingerückte Aufrufliste mit allen Parametern und Rückgabewerten.
|
||||||
|
|
||||||
|
**Ausgabeort:** Textdatei in `xdebug.output_dir`, mit `less` / `vim` lesbar.
|
||||||
|
|
||||||
|
Gezielt im Code, ohne Trigger:
|
||||||
|
|
||||||
|
```php
|
||||||
|
xdebug_start_trace('/tmp/meintrace');
|
||||||
|
// verdächtiger Abschnitt
|
||||||
|
xdebug_stop_trace();
|
||||||
|
```
|
||||||
|
|
||||||
|
Für die Frage „wer ruft das mit welchen Werten auf" meist schneller als ein Breakpoint.
|
||||||
|
|
||||||
|
### 5.3 Ebene 3: `debug` – Breakpoints
|
||||||
|
|
||||||
|
**Grundprinzip:** PHP verbindet sich **zur IDE**, nicht umgekehrt. Die IDE lauscht auf
|
||||||
|
Port 9003, PHP klopft an, sobald ein Request getriggert wird. Der Listener muss also
|
||||||
|
**vor** dem Request laufen – sonst passiert schlicht nichts.
|
||||||
|
|
||||||
|
**Wichtig bei eingeschränkten Systemen:** Der Client läuft auf der *eigenen* Maschine,
|
||||||
|
nicht auf dem Server. Wenn dort nichts installiert werden darf, hilft ein
|
||||||
|
SSH-Reverse-Tunnel:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -R 9003:localhost:9003 user@server
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Clients
|
||||||
|
|
||||||
|
| Client | Voraussetzung |
|
||||||
|
|---|---|
|
||||||
|
| **VS Code** | Extension „PHP Debug" (xdebug.php-debug) |
|
||||||
|
| **vdebug** (Vim/Neovim) | Vim mit `+python3`, spricht DBGp direkt – keine Node-Abhängigkeit |
|
||||||
|
| **nvim-dap** | Node + Adapter aus `vscode-php-debug` |
|
||||||
|
| **dbgp-tools** | reiner CLI-Client von Derick Rethans, via Composer |
|
||||||
|
|
||||||
|
**VS Code** – `.vscode/launch.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{ "name": "Listen for Xdebug", "type": "php", "request": "launch", "port": 9003 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`pathMappings` nur bei Remote/Docker/Lima nötig.
|
||||||
|
|
||||||
|
**vdebug** – `.vimrc`:
|
||||||
|
|
||||||
|
```vim
|
||||||
|
let g:vdebug_options = {
|
||||||
|
\ 'port': 9003,
|
||||||
|
\ 'break_on_open': 0,
|
||||||
|
\ 'path_maps': {'/var/www/projekt': '/home/sven/projekt'},
|
||||||
|
\}
|
||||||
|
```
|
||||||
|
|
||||||
|
`<F5>` Listener starten · `<F10>` Breakpoint setzen · `<F2>` Step Over
|
||||||
|
(`path_maps`: Serverpfad als Schlüssel)
|
||||||
|
|
||||||
|
**nvim-dap**:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
dap.adapters.php = {
|
||||||
|
type = 'executable',
|
||||||
|
command = 'node',
|
||||||
|
args = { os.getenv('HOME') .. '/.local/share/vscode-php-debug/out/phpDebug.js' }
|
||||||
|
}
|
||||||
|
dap.configurations.php = {
|
||||||
|
{ type = 'php', request = 'launch', name = 'Listen for Xdebug', port = 9003 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Request triggern
|
||||||
|
|
||||||
|
Wegen `start_with_request = trigger` wartet nicht jeder Request auf den Debugger:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://localhost/projekt/index.php?XDEBUG_TRIGGER=1
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
XDEBUG_TRIGGER=1 php script.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Bequemer: Browser-Extension **Xdebug Helper** (Chrome/Firefox) – ein Klick setzt ein
|
||||||
|
Cookie, danach ist jeder Request auf der Domain getriggert. Unerlässlich bei
|
||||||
|
POST-Formularen und Ajax, wo kein Query-Parameter angehängt werden kann.
|
||||||
|
|
||||||
|
#### Typischer Ablauf
|
||||||
|
|
||||||
|
1. Breakpoint in die interessierende Zeile setzen
|
||||||
|
2. Listener in der IDE starten (VS Code: F5)
|
||||||
|
3. Seite mit Trigger aufrufen → sie friert ein, die IDE springt nach vorn
|
||||||
|
4. Variablen im Scope, Call-Stack, Watch-Ausdrücke auswerten
|
||||||
|
(`$row['datum']`, `count($items)`, sogar Methodenaufrufe)
|
||||||
|
5. Step Over (F10) / Step Into (F11) / Continue (F5)
|
||||||
|
|
||||||
|
**Was man sieht:** Der Call-Stack ist meist der Aha-Moment – bei einem Fehler tief in
|
||||||
|
einem Repository sofort sichtbar, welcher Controller mit welchen Parametern ihn
|
||||||
|
ausgelöst hat.
|
||||||
|
|
||||||
|
**Conditional Breakpoints:** Rechtsklick auf den Breakpoint → Bedingung `$id === 4711`.
|
||||||
|
Damit gezielt bei einem Datensatz in einer Schleife über 10.000 Zeilen anhalten.
|
||||||
|
|
||||||
|
### 5.4 Profiling
|
||||||
|
|
||||||
|
Bei Performance-Fragen temporär umschalten:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
xdebug.mode = profile
|
||||||
|
xdebug.output_dir = /tmp
|
||||||
|
```
|
||||||
|
|
||||||
|
Schreibt `cachegrind.out.*`-Dateien, lesbar mit **qcachegrind**
|
||||||
|
(`brew install qcachegrind`) – zeigt, welche Funktion wie viel Zeit frisst.
|
||||||
|
|
||||||
|
> Nicht dauerhaft anlassen: bremst massiv und füllt `/tmp`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Alternative & Ergänzung: Symfony VarDumper
|
||||||
|
|
||||||
|
Unabhängig von Xdebug, rein per Composer – nützlich auf Systemen, wo keine Extension
|
||||||
|
installiert werden darf.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require --dev symfony/var-dumper
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
dump($row); // weiter im Code
|
||||||
|
dd($row, $other); // dump and die
|
||||||
|
```
|
||||||
|
|
||||||
|
Ausgabe im Browser aufklappbar, auf der CLI eingefärbt, kürzt rekursive Strukturen.
|
||||||
|
|
||||||
|
**Dump-Server** – fängt Ausgaben in einem separaten Terminal ab, statt sie in die
|
||||||
|
Response zu schreiben. Praktisch bei API-Endpunkten, wo HTML im Output stört:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vendor/bin/var-dump-server
|
||||||
|
# dazu: VAR_DUMPER_FORMAT=server
|
||||||
|
```
|
||||||
|
|
||||||
|
Versionszuordnung (Composer löst das automatisch auf):
|
||||||
|
|
||||||
|
| PHP | symfony/var-dumper |
|
||||||
|
|---|---|
|
||||||
|
| 7.1 | `^4.4` |
|
||||||
|
| 7.2 – 7.4 | `^5.4` |
|
||||||
|
| 8.0 – 8.1 | `^6.4` |
|
||||||
|
| 8.2+ | `^7` |
|
||||||
|
|
||||||
|
**Absolutes Minimum**, wenn gar nichts geht (Ajax, Redirects, Cronjobs):
|
||||||
|
|
||||||
|
```php
|
||||||
|
error_log(var_export($row, true));
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tail -f /var/log/apache2/error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Stolperfallen-Kurzliste
|
||||||
|
|
||||||
|
| Symptom | Ursache / Lösung |
|
||||||
|
|---|---|
|
||||||
|
| Extension wird ignoriert, keine Meldung | `extension=` statt `zend_extension=` |
|
||||||
|
| `incompatible architecture (have 'arm64', need 'x86_64')` | Build ohne Rosetta-Shell – `arch -x86_64 /bin/zsh`, dann neu bauen |
|
||||||
|
| `already installed ... install failed` | `pecl uninstall xdebug` oder `pecl install -f` |
|
||||||
|
| `Failed loading ... (no such file)` beim `pecl`-Aufruf | harmlos: PHP liest die INI, die `.so` wurde gerade gelöscht |
|
||||||
|
| `pecl` schreibt in falsche PHP-Installation | XAMPP-eigenes `pecl` aus `.../xamppfiles/bin/` verwenden |
|
||||||
|
| CLI zeigt Xdebug, Browser nicht | Apache lädt eine andere `php.ini` → Pfad aus `phpinfo()` nehmen |
|
||||||
|
| `var_dump` zeigt `...` statt Daten | `var_display_max_depth` / `_data` / `_children` erhöhen |
|
||||||
|
| Breakpoint wird nie erreicht | Listener nicht gestartet, oder Trigger fehlt |
|
||||||
|
| Port-Verbindung schlägt fehl | Xdebug 2 nutzt 9000, Xdebug 3 nutzt 9003 |
|
||||||
|
| `autoconf: command not found` | `brew install autoconf` |
|
||||||
|
| `Cannot find php-config` | falsches `phpize`/`php-config` – das aus dem Ziel-PHP nehmen |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Randnotiz: `var_dump` mit Barewords
|
||||||
|
|
||||||
|
```php
|
||||||
|
var_dump("Test", ffff); // ohne $
|
||||||
|
```
|
||||||
|
|
||||||
|
| PHP | Verhalten |
|
||||||
|
|---|---|
|
||||||
|
| ≤ 7.1 | `Notice: Use of undefined constant ffff` → gibt `string(4) "ffff"` aus |
|
||||||
|
| 7.2 – 7.4 | `Deprecated`, sonst wie oben |
|
||||||
|
| 8.0+ | **fataler** `Error: Undefined constant "ffff"` |
|
||||||
Reference in New Issue
Block a user