Compare commits

...
2 Commits
Author SHA1 Message Date
Sven Riwoldt c48157c54c SQL erweitert um Aufgabe 2026-08-27 14:40:38 +02:00
Sven Riwoldt 3b095316d4 Habe durch Claude noch Änderungen vornehmen lassen 2026-08-25 14:11:17 +02:00
2 changed files with 345 additions and 160 deletions
+26 -2
View File
@@ -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 icon](https://coddy.tech/icons/challenge-white.svg)
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
View File
@@ -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 $