Torbjorn Zetterlund

Tue 14 2023
Image

Xdebug a PHP docker container in VS Code

by bernt & torsten

This is the 2nd installment on debugging PHP applications running in a docker container with Xdebug on VS Code. You can find out how I set up a Docker Container for Apache + MySQL + PHP + Xdebug and Codeigniter on macOS using Docker. In this article, I will cover how you configure Xdebug for use with VS Code.

I am not going to beat around the bush, so here we go – to debug a PHP Docker container in Visual Studio Code, follow these steps:

  1. Install the PHP Debug extension in Visual Studio Code.
  2. In your Docker container, make sure Xdebug is installed and configured with the following settings in your php.ini file:
zend_extension=xdebug.so
xdebug.mode=develop,coverage,debug,profile
xdebug.idekey=docker
xdebug.start_with_request=yes
xdebug.log=/dev/stdout
xdebug.client_port=9003
xdebug.remote_host=host.docker.internal

In Visual Studio Code, create a launch configuration for debugging by opening the Debug panel (View > Debug), clicking the gear icon and selecting PHP. Add the following configuration to launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug on Docker",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "pathMappings": {
                "/var/www/html/": "${workspaceFolder}"
            }
        }
    ]
}
  1. Start the debugger by clicking the green play button in the Debug panel or by pressing. F5.
  2. Set a breakpoint in your code by clicking in the gutter to the left of the line you want to break on.
  3. Request the PHP script you want to debug. This will trigger the breakpoint, and you can inspect variables, step through code, and more in the Debug panel.
  4. When you are done debugging, stop the debugger by clicking the red square button in the Debug panel, or by pressing Shift + F5.

So let’s break it down a bit, so you know what each line means in the config file.

php.ini

zend_extension=xdebug.so
xdebug.mode=develop,coverage,debug,profile
xdebug.idekey=docker
xdebug.start_with_request=yes
xdebug.log=/dev/stdout
xdebug.client_port=9003
xdebug.remote_host=host.docker.internal
  • zend_extension=xdebug.so

A Zend extension hooks into “lower level” languages, and a single extension can be both a PHP and a Zend extension, despite being very uncommon it’s possible and Xdebug is a good example of it.

  • xdebug.mode=develop,coverage,debug,profile

This setting controls which Xdebug features got enabled, according to the documentation the following values gets accepted:

- develop
    Enables Development Helpers, including the overloaded var_dump().
- coverage
    Enables Code Coverage Analysis to generate code coverage reports, mainly with PHPUnit.
- debug
    Enables Step Debugging. This can be used to step through your code while it is running, and analyze values of variables.
- profile
    Enables Profiling, with which you can analyze performance bottlenecks with tools like CacheGrind.
  • xdebug.idekey=docker

Controls which IDE Key Xdebug should pass on to the debugging client or proxy. The IDE Key is only important for use with the DBGp Proxy Tool, although some IDEs are incorrectly picky as to what its value is. The default is based on the DBGP_IDEKEY environment setting. If it is not present, the default falls back to an empty string.

  • xdebug.start_with_request=yes

The functionality starts when the PHP request starts, and before any PHP code getting executed. For example, xdebug.mode=trace and xdebug.start_with_request=yes starts a Function Trace for the whole request.

  • xdebug.log=/dev/stdout

Configure Xdebug’s log file, but here, we are redirecting the log content to the default stdout of our container.

  • xdebug.client_port=9003

The port to which Xdebug tries to connect on the remote host. Port 9003 is the default for both Xdebug and the Command Line Debug Client. As many clients use this port number, it is best to leave this setting unchanged.

  • xdebug.remote_host=host.docker.internal

is a configuration setting for the Xdebug PHP extension. This setting specifies the hostname that Xdebug should use when connecting to a remote debugger.

host.docker.internal is a special hostname that resolves to the IP address of the host machine from within a Docker container. This allows Xdebug running in the Docker container to connect to a debugger running on the host machine, such as Visual Studio Code.

By setting xdebug.remote_host to host.docker.internal, Xdebug is able to establish a connection with the debugger on the host machine, allowing you to debug your PHP code running in the Docker container.

This setting is often used in development environments where the PHP code is running in a Docker container and the debugger is running on the host machine. It allows developers to take advantage of the benefits of containerization while still being able to debug their code in an integrated development environment (IDE).

launch.json VS Code

The launch.json file

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for Xdebug on Docker",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "pathMappings": {
                "/var/www/html/": "${workspaceFolder}"
            }
        }
    ]
}
  • name

Indicates the name given to a configuration object.

  • type

Indicates the underlying debugger getting used.

  • request

Indicates whether the configuration is intended to launch the program or attach to an already running instance.

  • port

Indicates the port on which to listen for Xdebug

  • pathMappings

Indicates a mapping of server paths to local paths.

When using /var/www/html/ as key, VSCode knows that the files at the container are under that path, and by using the ${workspaceFolder} as value, VSCode knows that locally the project files are under the current opened directory.

Troubleshooting

If Xdebug is not working as expected, here are some common issues and solutions:

  1. Make sure Xdebug is installed and enabled in your Docker container. You can check this by running php -m and verifying that Xdebug is listed among the modules.
  2. Check if the xdebug.so file exists in the correct location in your Docker container. This file is usually located in /usr/lib/php/<php-version>/.
  3. Make sure the xdebug.remote_host setting in your php.ini file is set to host.docker.internal. This is the hostname that will be used to connect from your local machine to the Docker container.
  4. Ensure that the port specified in your launch configuration (9000 in the example) is open and accessible from the Docker container. You may need to adjust the firewall settings on your machine to allow traffic on this port.
  5. Make sure the path mappings in your launch configuration are correct. The "/var/www/html"value should match the root path of your application in the Docker container, while "${workspaceFolder}" should match the local path on your machine where your code is stored.

If none of these solutions solve the issue, it may be helpful to consult the Xdebug documentation or seek assistance from the Xdebug community.

Share: