Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c48157c54c | ||
|
|
3b095316d4 |
@@ -558,13 +558,13 @@ select id, (id % 3) as quality_control from products where quantity % 2 = 1
|
||||
|
||||
## The ROUND() Function
|
||||
|
||||
Die Funktion `ROUND()` wird verwendet, um einen numerischen Wert auf eine bestimmte Anzahl von Nachkommastellen zu runden. Um die Funktion zu verwenden, folgt man diesem Syntax:
|
||||
Die Funktion `ROUND()` wird verwendet, um einen numerischen Wert auf eine bestimmte Anzahl von Nachkommastellen zu runden. Um die Funktion zu verwenden, folge dieser Syntax:
|
||||
|
||||
```sql
|
||||
ROUND(number, decimal_places)
|
||||
```
|
||||
|
||||
- `number`: Die Zahl, die man runden möchte
|
||||
- `number`: Die Zahl, die Sie runden möchten
|
||||
|
||||
- `decimal_places`: (Optional) Die Anzahl der Nachkommastellen, auf die gerundet werden soll
|
||||
|
||||
@@ -919,3 +919,27 @@ isys_catg_custom_fields_list__data__id,
|
||||
next 100 rows only;
|
||||
|
||||
##############################################################
|
||||
|
||||
Recap - Parliamentary Election
|
||||
|
||||

|
||||
|
||||
Challenge
|
||||
|
||||
Einfach
|
||||
|
||||
> Verfügbare Tabellen und Spalten:
|
||||
>
|
||||
> - `**ministers**`**:** `**seat**`**,** `**is_next_gov**`**,** `**is_spoke_bad**`
|
||||
|
||||
Jeder Minister, der auf einem geraden nummerierten Sitz in der Regierung sitzt, gilt als „sicherer“ Minister. Ihre Aufgabe ist es, alle `seats` der „sicheren“ Minister zurückzugeben, die weiterhin in der nächsten Regierung dienen möchten, während Sie jeden Minister ausschließen, der ein schlechtes Wort gesprochen hat.
|
||||
|
||||
Das Ergebnis sollte nur die relevanten Sitze enthalten.
|
||||
|
||||
Bevor Sie mit der Lösung der Herausforderung beginnen, werfen Sie einen Blick auf die Tabellendaten. **Sie sind nicht sauber**. Die Spalten `is_next_gov` und `is_spoke_bad` enthalten Einsen und Nullen sowie auch yes's und no's.
|
||||
|
||||
|
||||
|
||||
select seat from ministers where (seat % 2 = 0) and (is_spoke_bad = 0 or is_spoke_bad = 'no' )and (is_next_gov = 1 or is_next_gov = 'yes');
|
||||
|
||||
##############################################################
|
||||
|
||||
+319
-158
@@ -4,7 +4,34 @@ Stand: Xdebug 3.x (Modus-Konfiguration ab Xdebug 3, Port **9003**)
|
||||
|
||||
---
|
||||
|
||||
## 0. Vorab: Versionsmatrix
|
||||
## Die wichtigste Antwort vorweg
|
||||
|
||||
**Nein – man trägt nichts in die einzelnen PHP-Dateien ein.**
|
||||
|
||||
Xdebug wird **einmal** in der `php.ini` konfiguriert. Danach ist es für *jedes* PHP-Skript
|
||||
aktiv, das über diesen Webserver bzw. diese CLI läuft. Kein `require`, kein `include`,
|
||||
keine Zeile im Quellcode.
|
||||
|
||||
```
|
||||
php.ini ändern → Apache neu starten → gilt ab sofort überall
|
||||
```
|
||||
|
||||
Das `ini_set(...)` aus dem Gesprächsverlauf war ausdrücklich der **Notfallweg** für
|
||||
Systeme, auf denen man keine INI-Datei anfassen darf. Wer Zugriff auf die `php.ini` hat,
|
||||
braucht es nicht.
|
||||
|
||||
Im Code gibt es nur zwei *optionale* Dinge, die man punktuell einsetzen kann:
|
||||
|
||||
```php
|
||||
xdebug_break(); // setzt einen Breakpoint ohne IDE-Klick
|
||||
xdebug_start_trace('/tmp/xy'); // startet ein Aufrufprotokoll ab hier
|
||||
```
|
||||
|
||||
Beides ist Zusatzkomfort, keine Voraussetzung.
|
||||
|
||||
---
|
||||
|
||||
## 0. Versionsmatrix
|
||||
|
||||
| PHP | Xdebug | Konfigurationsstil |
|
||||
|---|---|---|
|
||||
@@ -17,7 +44,7 @@ Stand: Xdebug 3.x (Modus-Konfiguration ab Xdebug 3, Port **9003**)
|
||||
> `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.
|
||||
`20220829` = PHP 8.2 · `20230831` = PHP 8.3 · `20240924` = PHP 8.4
|
||||
|
||||
---
|
||||
|
||||
@@ -99,13 +126,9 @@ sudo cp modules/xdebug.so \
|
||||
/Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20220829/
|
||||
```
|
||||
|
||||
### 1.6 XAMPP-VM (macOS)
|
||||
### 1.6 Alternative ohne Compile-Schmerz
|
||||
|
||||
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
|
||||
Wer nicht an XAMPP gebunden ist:
|
||||
|
||||
```bash
|
||||
brew install php # natives arm64-PHP
|
||||
@@ -162,14 +185,6 @@ 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
|
||||
@@ -250,8 +265,6 @@ php -i | grep -E "Loaded Configuration|Scan this dir"
|
||||
|
||||
**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-…`**
|
||||
|
||||
@@ -286,7 +299,7 @@ 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
|
||||
### 4.3 Nur wenn keine INI-Datei erreichbar ist
|
||||
|
||||
**`.htaccess`** (nur bei mod_php, nicht FPM; erfordert `AllowOverride Options`):
|
||||
|
||||
@@ -302,6 +315,17 @@ ini_set('xdebug.var_display_max_depth', '10');
|
||||
ini_set('xdebug.var_display_max_data', '1024');
|
||||
```
|
||||
|
||||
Sinnvoll dann **einmal zentral** im Bootstrap, nicht in jeder Datei:
|
||||
|
||||
```php
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
if (($_ENV['APP_ENV'] ?? 'prod') === 'dev') {
|
||||
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)
|
||||
@@ -314,60 +338,249 @@ Zwei Fallstricke:
|
||||
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?
|
||||
## 5. Schritt für Schritt: Debuggen unter XAMPP (macOS/Windows)
|
||||
|
||||
Drei Ebenen, unabhängig voneinander nutzbar.
|
||||
Ausgangslage: Xdebug ist installiert, `php -v` zeigt „with Xdebug".
|
||||
|
||||
### 5.1 Ebene 1: `develop` – ohne jede Zusatzsoftware
|
||||
### Schritt 1 – Konfiguration eintragen (einmalig)
|
||||
|
||||
Aktiv allein durch `xdebug.mode = develop`:
|
||||
`php.ini` öffnen. Pfad zur *richtigen* Datei ermitteln:
|
||||
|
||||
- `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
|
||||
```bash
|
||||
# macOS
|
||||
/Applications/XAMPP/xamppfiles/bin/php -i | grep "Loaded Configuration"
|
||||
```
|
||||
```
|
||||
:: Windows
|
||||
C:\xampp\php\php.exe -i | findstr "Loaded Configuration"
|
||||
```
|
||||
|
||||
Zur Erinnerung – ohne Xdebug hilft `<pre>`, weil `var_dump` Plaintext ausgibt und der
|
||||
Browser Whitespace kollabiert:
|
||||
Am Ende der Datei eintragen (jede Direktive auf einer **eigenen Zeile**):
|
||||
|
||||
```ini
|
||||
[XDebug]
|
||||
zend_extension = /Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20220829/xdebug.so
|
||||
xdebug.mode = develop,debug
|
||||
xdebug.start_with_request = trigger
|
||||
xdebug.client_port = 9003
|
||||
xdebug.client_host = 127.0.0.1
|
||||
xdebug.var_display_max_depth = 10
|
||||
xdebug.var_display_max_data = 1024
|
||||
xdebug.var_display_max_children = 256
|
||||
```
|
||||
|
||||
Unter Windows genügt `zend_extension = xdebug`, weil die DLL in `ext\` liegt.
|
||||
|
||||
### Schritt 2 – Apache neu starten
|
||||
|
||||
```bash
|
||||
sudo /Applications/XAMPP/xamppfiles/xampp restart
|
||||
```
|
||||
|
||||
Windows: XAMPP Control Panel → Apache **Stop**, dann **Start**.
|
||||
|
||||
### Schritt 3 – Kontrollieren
|
||||
|
||||
Datei `htdocs/info.php` mit `<?php phpinfo();` anlegen, `http://localhost/info.php`
|
||||
aufrufen. Es muss ein eigener **Xdebug-Abschnitt** erscheinen. Danach Datei löschen.
|
||||
|
||||
Ab hier ist Xdebug für **alle** Skripte unter `htdocs/` aktiv – ohne weitere Eintragung.
|
||||
|
||||
### Schritt 4 – Erster Test ohne IDE
|
||||
|
||||
Beliebige Datei, z. B. `htdocs/test.php`:
|
||||
|
||||
```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>';
|
||||
<?php
|
||||
$daten = ['id' => 7, 'name' => 'Müller', 'rollen' => ['admin', 'user']];
|
||||
var_dump($daten);
|
||||
```
|
||||
|
||||
Aufrufen. Erwartetes Ergebnis: farbige, eingerückte Ausgabe mit Datei- und
|
||||
Zeilenangabe – **ohne** dass `<pre>` nötig wäre. Das ist der `develop`-Modus.
|
||||
|
||||
Ebenso: einen absichtlichen Fehler einbauen (`$x->foo();`) – statt der nackten
|
||||
PHP-Meldung kommt ein tabellarischer Stack-Trace mit allen Aufrufen und Parametern.
|
||||
|
||||
### Schritt 5 – Breakpoint-Debugging vorbereiten
|
||||
|
||||
**Grundprinzip verstehen:** PHP verbindet sich **zur IDE**, nicht umgekehrt. Die IDE
|
||||
lauscht auf Port 9003, PHP klopft an. Der Listener muss also **vor** dem Seitenaufruf
|
||||
laufen – sonst passiert schlicht nichts.
|
||||
|
||||
VS Code: Extension „PHP Debug" (xdebug.php-debug) installieren, dann im Projektordner
|
||||
`.vscode/launch.json` anlegen:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{ "name": "Listen for Xdebug", "type": "php", "request": "launch", "port": 9003 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`var_dump()` ist variadisch – mehrere Werte auf einmal sind erlaubt. Praktischer Trick
|
||||
zur Orientierung: `var_dump(__LINE__, $row);`
|
||||
`pathMappings` ist **nicht** nötig, weil Code und IDE auf derselben Maschine liegen.
|
||||
|
||||
### 5.2 Ebene 2: `trace` – Step-Debugging im Nachhinein
|
||||
### Schritt 6 – Breakpoint setzen und Session starten
|
||||
|
||||
Wenn keine IDE zur Verfügung steht, oft der stärkste Hebel.
|
||||
1. In `test.php` links neben die Zeilennummer klicken → roter Punkt erscheint
|
||||
2. **F5** drücken → unten wird die Statusleiste orange, VS Code lauscht jetzt
|
||||
3. Im Browser aufrufen: `http://localhost/test.php?XDEBUG_TRIGGER=1`
|
||||
4. Die Seite bleibt hängen, VS Code springt in den Vordergrund und markiert die Zeile
|
||||
|
||||
### Schritt 7 – Was man jetzt sieht
|
||||
|
||||
| Bereich in VS Code | Inhalt |
|
||||
|---|---|
|
||||
| **Variables** (links oben) | alle Variablen im aktuellen Scope, aufklappbar |
|
||||
| **Watch** | eigene Ausdrücke: `$daten['name']`, `count($items)`, Methodenaufrufe |
|
||||
| **Call Stack** | wer diese Funktion aufgerufen hat, mit Parametern – Klick springt dorthin |
|
||||
| **Breakpoints** | Liste aller gesetzten Haltepunkte |
|
||||
| **Debug Console** | beliebigen PHP-Code im aktuellen Kontext ausführen |
|
||||
|
||||
Steuerung: **F10** Step Over (nächste Zeile) · **F11** Step Into (in Funktion hinein) ·
|
||||
**Shift+F11** Step Out · **F5** Continue (bis zum nächsten Breakpoint)
|
||||
|
||||
### Schritt 8 – Trigger bequemer machen
|
||||
|
||||
Der Query-Parameter `?XDEBUG_TRIGGER=1` funktioniert nicht bei POST-Formularen oder
|
||||
Ajax. Lösung: Browser-Extension **Xdebug Helper** (Chrome/Firefox) – ein Klick auf den
|
||||
Käfer setzt ein Cookie, danach ist jeder Request auf der Domain getriggert.
|
||||
|
||||
CLI-Äquivalent:
|
||||
|
||||
```bash
|
||||
XDEBUG_TRIGGER=1 /Applications/XAMPP/xamppfiles/bin/php script.php
|
||||
```
|
||||
|
||||
### Schritt 9 – Session beenden
|
||||
|
||||
**Shift+F5** in VS Code stoppt den Listener. Die Seite im Browser läuft dann normal
|
||||
weiter. Ohne laufenden Listener werden Breakpoints einfach ignoriert – es entsteht kein
|
||||
Fehler.
|
||||
|
||||
---
|
||||
|
||||
## 6. Schritt für Schritt: Debuggen unter Debian
|
||||
|
||||
Zwei Fälle: Code liegt lokal auf demselben Rechner, oder auf einem entfernten Server.
|
||||
|
||||
### Schritt 1 – Installieren und konfigurieren
|
||||
|
||||
```bash
|
||||
sudo apt install php-xdebug
|
||||
sudo nano /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
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl restart apache2
|
||||
```
|
||||
|
||||
Für CLI-Skripte dieselbe Datei zusätzlich unter `/etc/php/8.4/cli/conf.d/` ablegen –
|
||||
oder einmal in `mods-available/` und mit `phpenmod xdebug-local` für beide aktivieren.
|
||||
|
||||
### Schritt 2 – Kontrollieren
|
||||
|
||||
```bash
|
||||
php -v # CLI: "with Xdebug v3.x.x"
|
||||
php -i | grep xdebug.mode
|
||||
```
|
||||
|
||||
Für den Webserver: `phpinfo()` im Browser aufrufen – nur das zeigt, was Apache lädt.
|
||||
Danach die Datei löschen.
|
||||
|
||||
### Schritt 3 – Client-Position klären
|
||||
|
||||
Der Debug-Client läuft auf **deiner** Maschine, nicht auf dem Server.
|
||||
|
||||
| Situation | Vorgehen |
|
||||
|---|---|
|
||||
| Code liegt lokal | nichts weiter nötig, Listener einfach starten |
|
||||
| Code auf entferntem Server | SSH-Reverse-Tunnel |
|
||||
|
||||
```bash
|
||||
ssh -R 9003:localhost:9003 user@server
|
||||
```
|
||||
|
||||
Damit verbindet sich Xdebug auf dem Server nach `localhost:9003` – und landet über den
|
||||
Tunnel bei dir. Der Tunnel muss offen bleiben, solange du debuggst.
|
||||
|
||||
### Schritt 4 – Pfade zuordnen (nur bei Remote)
|
||||
|
||||
Die IDE muss wissen, welche lokale Datei welchem Serverpfad entspricht.
|
||||
|
||||
VS Code, `.vscode/launch.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Listen for Xdebug",
|
||||
"type": "php",
|
||||
"request": "launch",
|
||||
"port": 9003,
|
||||
"pathMappings": {
|
||||
"/var/www/projekt": "${workspaceFolder}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Links steht immer der **Serverpfad**, rechts der lokale. Stimmt das nicht, hält der
|
||||
Debugger zwar an, öffnet aber keine Datei – der häufigste Frustpunkt bei Remote-Setups.
|
||||
|
||||
### Schritt 5 – Ohne VS Code: vdebug in Vim/Neovim
|
||||
|
||||
Spricht DBGp direkt, braucht nur Vim mit `+python3` – keine Node-Abhängigkeit.
|
||||
|
||||
`.vimrc`:
|
||||
|
||||
```vim
|
||||
let g:vdebug_options = {
|
||||
\ 'port': 9003,
|
||||
\ 'break_on_open': 0,
|
||||
\ 'path_maps': {'/var/www/projekt': '/home/sven/projekt'},
|
||||
\}
|
||||
```
|
||||
|
||||
Bedienung: **F5** Listener starten · **F10** Breakpoint setzen/entfernen ·
|
||||
**F2** Step Over · **F3** Step Into · **F4** Step Out · **F6** beenden
|
||||
|
||||
Sobald die Session steht, teilt sich das Fenster: Quellcode, Variablen im aktuellen
|
||||
Scope, Call-Stack und ein Watch-Bereich, in dem sich beliebige Ausdrücke auswerten
|
||||
lassen.
|
||||
|
||||
Alternativen: **nvim-dap** (moderneres UI, braucht Node + `vscode-php-debug`) und
|
||||
**dbgp-tools** von Derick Rethans (reiner CLI-Client, via Composer).
|
||||
|
||||
### Schritt 6 – Request triggern
|
||||
|
||||
```bash
|
||||
# Webseite
|
||||
http://server/projekt/index.php?XDEBUG_TRIGGER=1
|
||||
|
||||
# CLI-Skript auf dem Server
|
||||
XDEBUG_TRIGGER=1 php artisan irgendwas
|
||||
```
|
||||
|
||||
### Schritt 7 – Wenn keine IDE möglich ist: Trace-Dateien
|
||||
|
||||
Auf gesperrten Systemen oft der stärkste Hebel – ein Step-Debugger im Nachhinein.
|
||||
|
||||
```ini
|
||||
xdebug.mode = develop,trace
|
||||
@@ -379,11 +592,13 @@ 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.
|
||||
eingerückte Aufrufliste mit allen Parametern und Rückgabewerten:
|
||||
|
||||
**Ausgabeort:** Textdatei in `xdebug.output_dir`, mit `less` / `vim` lesbar.
|
||||
```bash
|
||||
ls -t /tmp/trace.*.xt | head -1 | xargs less
|
||||
```
|
||||
|
||||
Gezielt im Code, ohne Trigger:
|
||||
Gezielt nur einen Abschnitt protokollieren:
|
||||
|
||||
```php
|
||||
xdebug_start_trace('/tmp/meintrace');
|
||||
@@ -393,117 +608,47 @@ 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.
|
||||
## 7. Was man wo sieht – Überblick
|
||||
|
||||
**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:
|
||||
| Modus | Ausgabeort | Zeigt |
|
||||
|---|---|---|
|
||||
| `develop` | Browser / STDOUT | farbiges `var_dump`, Stack-Traces bei Fehlern |
|
||||
| `trace` | Datei in `xdebug.output_dir` | kompletter Aufrufbaum mit Parametern |
|
||||
| `debug` | IDE / Vim | Variablen, Call-Stack, Watch, schrittweise Ausführung |
|
||||
| `profile` | `cachegrind.out.*` in `output_dir` | Laufzeit pro Funktion (qcachegrind) |
|
||||
|
||||
```bash
|
||||
ssh -R 9003:localhost:9003 user@server
|
||||
Zusätzlich im Code nutzbar (alle Modi):
|
||||
|
||||
```php
|
||||
xdebug_info(); // Konfigurations-Übersicht im Browser
|
||||
xdebug_break(); // Breakpoint aus dem Code heraus
|
||||
var_dump(xdebug_get_function_stack()); // Wer hat mich aufgerufen?
|
||||
error_log(xdebug_print_function_stack()); // Stack ins Logfile
|
||||
echo xdebug_call_line();
|
||||
```
|
||||
|
||||
#### Clients
|
||||
### Conditional Breakpoints
|
||||
|
||||
| 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 |
|
||||
Rechtsklick auf den Breakpoint → Bedingung eintragen, z. B. `$id === 4711`. Damit hält
|
||||
man gezielt bei einem Datensatz in einer Schleife über 10.000 Zeilen an. Einer der
|
||||
größten praktischen Vorteile gegenüber `var_dump`.
|
||||
|
||||
**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:
|
||||
### Profiling
|
||||
|
||||
```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.
|
||||
Auswertung mit **qcachegrind** (`brew install qcachegrind`, `apt install kcachegrind`).
|
||||
|
||||
> Nicht dauerhaft anlassen: bremst massiv und füllt `/tmp`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Alternative & Ergänzung: Symfony VarDumper
|
||||
## 8. Alternative & Ergänzung: Symfony VarDumper
|
||||
|
||||
Unabhängig von Xdebug, rein per Composer – nützlich auf Systemen, wo keine Extension
|
||||
installiert werden darf.
|
||||
@@ -527,8 +672,6 @@ 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` |
|
||||
@@ -546,9 +689,24 @@ error_log(var_export($row, true));
|
||||
tail -f /var/log/apache2/error.log
|
||||
```
|
||||
|
||||
### Ohne Xdebug: `<pre>` nicht vergessen
|
||||
|
||||
`var_dump()` gibt Plaintext aus, der Browser kollabiert Whitespace. Deshalb:
|
||||
|
||||
```php
|
||||
function dbg(...$vars): void {
|
||||
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);`
|
||||
|
||||
---
|
||||
|
||||
## 7. Stolperfallen-Kurzliste
|
||||
## 9. Stolperfallen-Kurzliste
|
||||
|
||||
| Symptom | Ursache / Lösung |
|
||||
|---|---|
|
||||
@@ -558,15 +716,18 @@ tail -f /var/log/apache2/error.log
|
||||
| `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 |
|
||||
| Direktiven wirken nicht | alles in einer Zeile statt untereinander |
|
||||
| `<datum>` im Pfad | Platzhalter! echten Namen per `php -i \| grep extension_dir` ermitteln |
|
||||
| `var_dump` zeigt `...` statt Daten | `var_display_max_depth` / `_data` / `_children` erhöhen |
|
||||
| Breakpoint wird nie erreicht | Listener nicht gestartet, oder Trigger fehlt |
|
||||
| Debugger hält an, öffnet aber keine Datei | `pathMappings` / `path_maps` falsch (Serverpfad links) |
|
||||
| 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
|
||||
## 10. Randnotiz: `var_dump` mit Barewords
|
||||
|
||||
```php
|
||||
var_dump("Test", ffff); // ohne $
|
||||
|
||||
Reference in New Issue
Block a user