Php debugging
Universal AI Agent OS — audited skills, governance rules, replayable state. One contract, every host agent.
npx -y skills add event4u-app/agent-config --skill php-debuggingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
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'.
SKILL.md
8.0 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
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
- Detect the project's debug setup — check
docker-compose.yml/compose.yamlfor Xdebug containers. - Check Dockerfile — look for a
dev-xdebugbuild stage or Xdebug installation. - Check NGINX config — look for header-based routing to a debug container.
- Read project docs — check
Docs/XDEBUG_SETUP.mdordocs/for setup instructions. - Check
.env— look forDOCKER_XDEBUG_MODEandDOCKER_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:
# 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
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
- Debug port: Settings → PHP → Debug → Port:
9003 - Enable listening: Click "Start Listening for PHP Debug Connections" (phone icon)
- Server config: Settings → PHP → Servers:
- Host:
localhost, Port:80(internal container port, not host port) - Enable path mappings: local project root →
/var/www/html
- Host:
- Browser extension: Install "Xdebug helper", set IDE key to
PHPSTORM
VS Code
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
}
}
Debugging workflow
- Start listening in IDE (PhpStorm: green phone icon)
- Set breakpoints in code
- Send request with debug header (browser extension, Postman, or curl)
- IDE breaks at breakpoint → inspect variables, step through code
- Check
X-PHP-Backendheader if debugging doesn't trigger
CLI debugging (Artisan commands, tests)
For debugging Artisan commands or tests, enter the Xdebug container:
make console-xdebug # Enter Xdebug container
php artisan your:command # Xdebug connects to IDE automatically
Verifying CLI fixes
After a fix, verify the command without re-attaching the debugger:
# Run the command, capture exit code + command output
php artisan your:command; echo "exit code: $?"
# Pest CLI assertion — expectsOutput / artisan test
vendor/bin/pest --filter='ProcessInvoicesCommand'
Assert on the exit code and command output; never trust "looks fine" from breakpoint inspection alone.
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
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
Filter noisy debug output
tail -f /tmp/xdebug.log and docker logs produce far too much
data to read line-by-line. Filter with rg/grep for the relevant
event:
# Only connection / breakpoint events
rg --color=never 'Connect|Step|breakpoint' /tmp/xdebug.log
# Only this request's frames in the laravel log
docker compose logs php-xdebug | rg --color=never "$REQUEST_ID"
What NOT to do
- Do not leave Xdebug enabled in production containers.
- Do not use underscores in debug headers (
XDEBUG_SESSIONfails — useXDEBUG-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
- Xdebug configuration or debugging session setup
- 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()orvar_dump()— they're forbidden by PHPStan config. Use Xdebug breakpoints. - Step-debugging over HTTP requires the
XDEBUG_SESSIONcookie/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.
Clarification guard — ambiguous repro → ask
If the bug repro is unclear (which request, which user, which env, which input shape?), do not start placing breakpoints at random. Ask the user for the failing payload, the exact route, or the Sentry trace. Setting breakpoints based on a guessed flow wastes a session.
Auto-trigger keywords
- Xdebug
- PHP debugging
- breakpoint
- step debugging
Known Laravel bug patterns (from bug-analyzer)
- N+1 queries hidden in loops or accessors
- Missing
->fresh()after update when using same instance - Eloquent lazy loading in queued jobs (serialization issues)
now()timezone mismatches- Missing FK constraints allowing orphaned records
DB::transaction()with external side effects (emails, API calls)- Model events firing during seeding or migration
- Off-by-one errors in pagination or date ranges
- Silent exception swallowing (
catch (\Exception $e) {}) - Floating point comparison for money/quantities