Step-debugging with Xdebug¶
Every ddev project is automatically configured with xdebug so that popular IDEs can do step-debugging of PHP code. It is disabled by default for performance reasons, so you'll need to enable it in your config.yaml.
xdebug is a server-side tool: It is installed automatically on the container and you do not need to install or configure it on your workstation.
All IDEs basically work the same: They listen on a port and react when they're contacted there. IDEs other than those listed here work fine, if they listen on the default xdebug port 9003. (This was port 9000 through DDEV v1.18, changed to 9003 in v1.19+)
Key facts:
- Enable xdebug by running
ddev xdebug
orddev xdebug on
in your project directory. It will remain enabled until you start or restart the project. - Disable xdebug for better performance when not debugging with
ddev xdebug off
ddev xdebug status
will show current status.- The debug server port on the IDE must be set to port 9003 (port 9000 before v1.19), which is the default and is probably already set in most popular IDEs. (If you need to change the xdebug port due to a port conflict on your host computer, you can do it with a PHP override, explained below.)
For more background on XDebug see XDebug documentation. The intention here is that one won't have to understand XDebug to do debugging.
For each IDE the link to their documentation is provided, and the skeleton steps required are listed here.
Setup for Various IDEs¶
PhpStorm Debugging Setup¶
PhpStorm is a leading PHP development IDE with extensive built-in debugging support. It provides two different ways to do debugging. One requires very little effort in the PhpStorm IDE (they call it zero-configuration debugging) and the other requires you to set up a "run configuration", and is basically identical to the Netbeans or Eclipse setup.
If you are using PhpStorm inside WSL2 (or perhaps other Linux configurations), under Help→ Edit Custom VM Options
, add an additional line: -Djava.net.preferIPv4Stack=true
This makes PhpStorm listen for Xdebug using IPV4; the Linux version of PhpStorm seems to default to using only IPV6.
PhpStorm Zero-Configuration Debugging¶
PhpStorm zero-configuration debugging will automatically detect a connection and offer to create a "server", a file mapping from your workstation to the container. This means you only have to:
- Toggle the “Start Listening for PHP Debug Connections” button:
- Set a breakpoint.
- Visit a page that should stop in the breakpoint you set.
- PhpStorm will ask you what mapping to use, so it can figure out how to map the path inside the container to the path on your workstation. The first time you do this with a project, PhpStorm will pop up a "server" dialog box to set the mapping. The default will work, but it's best to click the checkbox to map the whole project directory to /var/www/html.
Note when using this recommended option:
- Please use the latest DDEV version.
- Under Run >> Edit Configurations, check that there are no "Servers" already defined. PhpStorm will create a new "Server" (file mapping) for you as discussed above, but only if you don't already have one. You can delete all servers and have PhpStorm create a new one, or you can create/edit an existing server as discussed below.
PhpStorm "Run/Debug configuration" Debugging¶
PhpStorm run/debug configurations require slightly more up-front work but can offer more flexibility and may be easier for some people.
- Under the "Run" menu select "Edit configurations"
- Click the "+" in the upper left and choose "PHP Web Application" to create a configuration. Give it a reasonable name.
- Create a "server" for the project. Make sure that "Name" is exactly the same as your "host" (e.g.
my-site.ddev.site
) (Screenshot below) - Add file mappings for the files on the server. Click on the local repo path and add "/var/www/html" as the "Absolute path on the server" and your repository root as the path on the host.
- Set an appropriate breakpoint.
- Start debugging by clicking the "debug" button, which will launch a page in your browser.
Server creation:
PhpStorm and Command-Line Debugging¶
If you need to debug command-line PHP processes, especially code that is outside the docroot, the environment variable PHP_IDE_CONFIG is already set inside the web container, so you don't have to do much more.
However, if you have not yet used PhpStorm with xdebug for a regular web request, do that to automatically create the PhpStorm "server" with the same name as your primary URL (see "Languages and Frameworks" -> "PHP" -> "Servers"). The key job of the "server" is to map filesystem locations on the workstation (your computer) to filesystem locations on the remote server (in this case the ddev-webserver container). Often, PhpStorm has automatically set up a mapping that doesn't include the entire project (so the vendor directory is not mapped, for example). So map the top-level directory of your project to /var/www/html in the container, as in this image:
Visual Studio Code (vscode) Debugging Setup¶
- Install the php-debug extension.
- Update the project's [launch.json] (in
.vscode/launch.json
) to add "Listen for xdebug" (see config snippet). For more on launch.json, see vscode docs. - Set a breakpoint in your index.php. If it isn't solid red, restart.
- In the menu, choose Run->Start Debugging.You may have to select "Listen for XDebug" by the green arrowhead at the top left. The bottom pane of vscode should now be orange (live) and should say "Listen for XDebug".
- Enable XDebug with
ddev xdebug on
- In a browser, visit your project, you should hit the breakpoint.
Note that if you're using vscode on Windows with WSL2, you'll want the "PHP Debug" extension enabled in your distro (for example, Ubuntu). You'll also need the "Remote - WSL" extension enabled. vscode will suggest both of these to you if you have WSL2 enabled and a PHP project.
Using Xdebug on a Port Other than the Default 9003¶
By default, ddev is set up to contact the default port, port 9003 on your IDE. However, if you have something else listening on that port or your IDE does not yet default to 9003, you'll need to change the port. (PhpStorm and vscode have switch to supporting 9003 instead of 9000 for some time now.)
- To override the port, add an override file in the project's .ddev/php directory. For example, a file .ddev/php/xdebug_client_port.ini would change to use the traditional old port 9000:
- Then change your IDE's configuration to listen on the new port.
NOTE: If you are using a PHP version below PHP7.2, you will be using Xdebug version 2.x, instead of 3.x. In that case the port config should be xdebug.remote_port
instead.
Troubleshooting Xdebug¶
The basic thing to understand about xdebug is that it's a network protocol. Your IDE (like PhpStorm) will listen on the xdebug port (9003 by default in v1.19+, previously 9000). Then if xdebug is enabled in the ddev web container with ddev xdebug on
, then php inside the container will try to open a TCP connection to the IDE. Docker's networking places the host-side listening IDE at host.docker.internal:9003
. So you have to make sure that the network connection is clear and can be made and everything should work. Here are basic steps to take to sort out any difficulty:
- Remember that the port in play is port 9003 for DDEV v1.19+, but before that it was port 9000.
- Reboot your computer.
- Temporarily disable any firewall or VPN if you're having trouble. Xdebug is a network protocol, and the php process inside the web container must be able to establish a TCP connection to the listening IDE (PhpStorm, for example).
- Use
ddev xdebug on
to enable xdebug when you want it, andddev xdebug off
when you're done with it. - Set a breakpoint at the first executable line of your index.php.
- Tell your IDE to start listening. (PhpStorm: Click the telephone button, vscode: run the debugger.)
- Use
curl
or a browser to create a web request. For example,curl https://d9.ddev.site
- If the IDE doesn't respond, take a look at
ddev logs
. If you see a message like ""PHP message: Xdebug: [Step Debug] Could not connect to debugging client. Tried: host.docker.internal:9003 (through xdebug.client_host/xdebug.client_port)" then php/xdebug (inside the container) is not able to make a connection to port 9003. ddev ssh
into the web container. Can youtelnet host.docker.internal 9003
and have it connect? If you can't, you might have an over-aggressive firewall. Disable it, or add a rule that would allow the connection to pass through. For example, on Debian/ Ubuntu that would besudo ufw allow 9003/tcp
.- In PhpStorm, disable the "listen for connections" button so it won't listen. Or just exit PhpStorm. With another IDE like vscode, stop the debugger from listening.
ddev ssh
: Cantelnet host.docker.internal 9003
connect? If it does, you have something else running on port 9003. On the host, usesudo lsof -i :9003 -sTCP:LISTEN
to find out what is there and stop it. Don't continue debugging until your telnet command does not connect. (Note that on Windows WSL2 you may have to look for listeners both inside WSL2 and on the Windows side.)- Now click the listen button on PhpStorm to start it listening for connections.
ddev ssh
and try thetelnet host.docker.internal 9003
again. It should connect. If not, maybe PhpStorm is not listening, or not configured to listen on port 9003?- Check to make sure that Xdebug is enabled. You can use
php -i | grep -i xdebug
inside the container, or use any other technique you want that gives the output ofphpinfo()
, including Drupal's admin/reports/status/php. You should seewith Xdebug v3
andphp -i | grep xdebug.mode
should give youxdebug.mode => debug,develop => debug,develop"
. - Set a breakpoint in the first relevant line of the index.php of your project and then visit the site in a browser. It should stop at that first line.
- If you are using PhpStorm inside WSL2 (or perhaps other Linux configurations), under
Help→ Edit Custom VM Options
, add an additional line:-Djava.net.preferIPv4Stack=true
This makes PhpStorm listen for Xdebug using IPV4; the Linux version of PhpStorm seems to default to using only IPV6. - If you are on WSL2 using Docker Desktop, make sure that the
docker
command is the one provided by Docker Desktop.ls -l $(which docker)
should show a link to/mnt/wsl/docker-desktop...
. If you are on WSL2 using docker installed inside WSL2, make sure thatls -l $(which docker)
is not a link to/mnt/wsl
.