Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install event4u-app-agent-config-agent-src-uncompressed-skills-php-debugginggit clone https://github.com/event4u-app/agent-config.gitcp agent-config/SKILL.MD ~/.claude/skills/event4u-app-agent-config-agent-src-uncompressed-skills-php-debugging/SKILL.md---
name: php-debugging
description: "Use when debugging PHP with Xdebug — breakpoints, step-through, dual-container setup, IDE configuration, header-based routing — even when the user just says 'why does this blow up on request X'."
source: package
domain: engineering
---
# php-debugging
## When to use
Use this skill when:
- Setting up or troubleshooting Xdebug
- Debugging PHP code with breakpoints
- Investigating performance issues
- Running code coverage
- Helping users configure their IDE for debugging
This skill extends `php-coder` and `php`.
## Procedure: Debug with Xdebug
1. **Detect the project's debug setup** — check `docker-compose.yml` / `compose.yaml` for Xdebug containers.
2. **Check Dockerfile** — look for a `dev-xdebug` build stage or Xdebug installation.
3. **Check NGINX config** — look for header-based routing to a debug container.
4. **Read project docs** — check `Docs/XDEBUG_SETUP.md` or `docs/` for setup instructions.
5. **Check `.env`** — look for `DOCKER_XDEBUG_MODE` and `DOCKER_XDEBUG_PORT`.
## Dual-container architecture
Many projects use two PHP containers for optimal performance:
| Container | Purpose | When used |
|---|---|---|
| `*-php` | Fast PHP-FPM, no Xdebug overhead | All normal requests |
| `*-php-xdebug` | PHP-FPM with Xdebug enabled | Only debug requests |
NGINX routes requests based on HTTP headers:
- **No debug header** → fast container (no Xdebug)
- **Debug header present** → Xdebug container
### Debug headers
| Header | Value | Recommended for |
|---|---|---|
| `X-Xdebug-Enable` | `1` or `true` | Manual tests, Postman |
| `X-Debug-Session` | `PHPSTORM` | IDE integration |
| `XDEBUG-SESSION` | any value | Standard Xdebug header |
**Important:** Use hyphens, not underscores. `XDEBUG_SESSION` does NOT work — use `XDEBUG-SESSION`.
### Verify routing
Check the `X-PHP-Backend` response header to confirm which container handled the request:
```bash
# Normal request
curl -I http://localhost:8002/ # → X-PHP-Backend: *-php:9000
# Debug request
curl -I -H "X-Xdebug-Enable: 1" http://localhost:8002/ # → X-PHP-Backend: *-php-xdebug:9000
```
## Xdebug configuration
### Environment variables
```bash
DOCKER_XDEBUG_MODE=develop,debug,coverage # Xdebug modes
DOCKER_XDEBUG_PORT=9003 # IDE listens on this port
```
### Xdebug modes
| Mode | Purpose |
|---|---|
| `debug` | Step debugging with breakpoints |
| `develop` | Enhanced error messages, var_dump improvements |
| `coverage` | Code coverage for tests |
| `profile` | Performance profiling (generates cachegrind files) |
| `trace` | Function call tracing |
### PHP-FPM on-demand (Xdebug container)
The Xdebug container typically uses `pm = ondemand` to save resources:
- Workers start only when a debug request arrives
- Idle workers terminate after 60s
- Reduces memory usage by ~60-70% when not debugging
- Unlimited request timeout for breakpoint sessions
## IDE setup
### PhpStorm
1. **Debug port**: Settings → PHP → Debug → Port: `9003`
2. **Enable listening**: Click "Start Listening for PHP Debug Connections" (phone icon)
3. **Server config**: Settings → PHP → Servers:
- Host: `localhost`, Port: `80` (internal container port, not host port)
- Enable path mappings: local project root → `/var/www/html`
4. **Browser extension**: Install "Xdebug helper", set IDE key to `PHPSTORM`
### VS Code
```json
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
}
}
```
## Debugging workflow
1. **Start listening** in IDE (PhpStorm: green phone icon)
2. **Set breakpoints** in code
3. **Send request with debug header** (browser extension, Postman, or curl)
4. **IDE breaks** at breakpoint → inspect variables, step through code
5. **Check `X-PHP-Backend` header** if debugging doesn't trigger
## CLI debugging (Artisan commands, tests)
For debugging Artisan commands or tests, enter the Xdebug container:
```bash
make console-xdebug # Enter Xdebug container
php artisan your:command # Xdebug connects to IDE automatically
```
## Troubleshooting
| Problem | Solution |
|---|---|
| Breakpoints not hit | Check IDE is listening, verify path mappings, check `X-PHP-Backend` header |
| IDE not connecting | `make console-xdebug` then `nc -zv host.docker.internal 9003` — should show "open" |
| Wrong container used | Check response header `X-PHP-Backend`, verify debug header format (hyphens!) |
| Slow normal requests | Verify normal requests go to fast container (no `X-PHP-Backend: *-xdebug*`) |
| Xdebug logs | `make console-xdebug` then `tail -f /tmp/xdebug.log` |
| Container not running | `docker compose ps` — both PHP containers should be "Up" |
| Path mapping wrong | PhpStorm: Settings → PHP → Servers → verify local ↔ `/var/www/html` |
## Container management
```bash
make console # Fast PHP container (no Xdebug)
make console-xdebug # Xdebug container
make rebuild-php-xdebug # Rebuild Xdebug container only
make rebuild-php-all # Rebuild both PHP containers
```
## What NOT to do
- Do not leave Xdebug enabled in production containers.
- Do not use underscores in debug headers (`XDEBUG_SESSION` fails — use `XDEBUG-SESSION`).
- Do not set PhpStorm server port to the host port (e.g. 8002) — use the internal port (80).
- Do not run performance benchmarks against the Xdebug container.
- Do not forget to check path mappings when breakpoints are silently skipped.
## Output format
1. Xdebug configuration or debugging session setup
2. Root cause identified with evidence from debugger output
## Gotcha
- Xdebug runs in a separate container — don't confuse the fast container (port 80) with the debug container (port 8080).
- The model tends to suggest `dd()` or `var_dump()` — they're forbidden by PHPStan config. Use Xdebug breakpoints.
- Step-debugging over HTTP requires the `XDEBUG_SESSION` cookie/header — without it, breakpoints don't trigger.
## Do NOT
- Do NOT leave breakpoints or debug code in committed files.
- Do NOT use var_dump() or dd() — use Xdebug breakpoints.
- Do NOT debug in the fast container — switch to the Xdebug container.
## Auto-trigger keywords
- Xdebug
- PHP debugging
- breakpoint
- step debugging