CCelestiallines.com
← Back to blog

How to Debug PHP with Xdebug in VS Code

By Pawan Singh · Jun 2026

Stepping through PHP execution line-by-line, inspecting real variable state, beats var_dump-and-refresh debugging for anything non-trivial. Here's the full setup, plus the parts that actually go wrong (Docker, WSL, remote servers).

Install the Xdebug Extension

Xdebug is a PECL extension, not a bundled PHP feature. Install it for your specific PHP version and OS:

pecl install xdebug

Then enable it in php.ini and configure it to talk to your editor:

zend_extension=xdebug.so
xdebug.mode=debug
xdebug.start_with_request=trigger
xdebug.client_host=127.0.0.1
xdebug.client_port=9003

Confirm it loaded with php -v — it should print an Xdebug line alongside the PHP version. Port 9003 is Xdebug 3's default (Xdebug 2 used 9000, a common source of confusion when following outdated tutorials).

Install the VS Code Extension

Install "PHP Debug" (by Xdebug's own maintainer, xdebug.org) from the VS Code marketplace. It provides the launch.json configuration type that speaks the Xdebug protocol.

Configure launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug",
            "type": "php",
            "request": "launch",
            "port": 9003
        }
    ]
}

Start this configuration (F5), set a breakpoint by clicking in the gutter next to a line number, then trigger the request — load the page in a browser, or run the script from the CLI. Execution pauses at the breakpoint, and the Debug sidebar shows the full variable scope, call stack, and lets you step in/over/out.

Debugging Inside Docker or DDEV

This is where most setups actually break: Xdebug running inside a container needs to reach your editor on the host machine, not localhost from the container's own perspective. Set:

xdebug.client_host=host.docker.internal

DDEV-based projects (Drupal, Laravel, or otherwise) have this largely handled already — ddev xdebug on enables it with the right host configuration for you, and ddev xdebug off disables it again (leaving it on permanently adds real overhead to every request, so toggle it only when actively debugging).

Debugging from WSL

If your PHP process runs inside WSL but VS Code (or its window) is on Windows, set xdebug.client_host to the actual IP WSL uses to reach Windows — not always 127.0.0.1, depending on your WSL networking mode. Run cat /etc/resolv.conf inside WSL to find the nameserver IP, which is usually also the right host IP for this purpose in WSL2's default NAT networking mode.

Conditional and Logpoint Breakpoints

Right-click a breakpoint to add a condition (e.g. $userId === 42) so it only pauses on the iteration you actually care about inside a loop — far faster than manually stepping through hundreds of irrelevant iterations. Logpoints (also right-click) print a message to the debug console without pausing execution at all, a lower-friction alternative to temporary error_log() calls you'd otherwise have to remember to remove.

Common Issues

  • "Could not connect to debugging client" in the browser — check xdebug.client_host matches where your editor is actually listening, especially across Docker/WSL boundaries.
  • Debugger never triggers — with xdebug.start_with_request=trigger, you need a trigger: either a browser extension that sets the XDEBUG_TRIGGER cookie, or append ?XDEBUG_TRIGGER=1 to the URL manually.
  • Everything feels slow — set xdebug.start_with_request=trigger instead of yes/always, so Xdebug's overhead only applies to requests you're explicitly debugging.
  • Breakpoints show as unbound (hollow) circles — usually a path mapping mismatch between the file VS Code has open and the path Xdebug reports from inside a container; add a pathMappings entry to launch.json matching your container's filesystem layout.
  • Works for web requests, not CLI scripts — CLI runs need xdebug.mode=debug exported in the shell's environment too, since CLI PHP doesn't always read the same effective php.ini as your web server's PHP-FPM pool.

Need your local dev environment set up properly, debugging included? Get in touch — I work as a freelance PHP developer.

Comments