Xdebug for PHP developers – PhpStorm and Docker

Xdebug allows you to break code execution to see the state/value of the current instantiated variables/objects, test object methods, and pass through all logical steps.

It also allows you to modify variables/objects on the fly, affecting the execution of your script during one iteration and running cycle.  What this means is you have everything you need to troubleshoot and track down the issues and be more efficient.

Many PHP IDEs support Xdebug integration but in this text, I will be explaining how to configure Xdebug on a PhpStorm running with Docker.

Installation

To run it you need to install and integrate the Xdebug extension. Basic installation is mostly done using pecl (package with repository for PHP extensions).

Our dev environment will be run inside docker containers, so we need to add an installation command inside Dockerfile.

RUN pecl install xdebug

Enable the Xdebug extension must be added to php.ini or any custom ini you want to use as an addition to the default PHP ini files.

Basic configuration for Xdebug 3:

#enabling extension
zend_extension=xdebug.so
#setting xdebug working mode. In version 3, you can specify multiple modes separated by comma 
xdebug.mode = debug

#If enabled, this setting will activate the discovery of the client's IP address. It's set to 0 because we are going to use the static IP address of the host IP running Docker.
xdebug.discover_client_host=0
#static IP address of the host machine from docker container for OsX and Windows use host.docker.internal
xdebug.client_host=172.17.0.1
#default xdebug 3 port
xdebug.client_port = 9003
#PHP IDE trigger key if set, for example, in request URL, it will trigger activation of xdebug
xdebug.idekey = PHPSTORM
#setting the limit of how deep nesting/recurring requests can go 
xdebug.max_nesting_level = 12256
#logging file for xdebug where we can see the details of xdebug execution or check if xdebug is not working correctly
xdebug.log = /app/var/log/xdebugaa.log
#activating Xdebug before each PHP request (helpful when debugging PHP execution from console)
xdebug.start_with_request=yes

Find more xdebug settings on: https://xdebug.org/docs/all_settings

Basic configuration for Xdebug 2:

#enabling extension
zend_extension=xdebug.so
#enabling xdebug debug mode
xdebug.remote_enable=1
#activating xdebug before each PHP request
xdebug.remote_autostart=1
#PHP IDE trigger key if set for example in request url, it will trigger activation of xdebug
xdebug.idekey=PHPSTORM
#setting the limit of how deep nesting/recurring request can go
xdebug.max_nesting_level=120000
#if enabled, this setting will activate the discovery of the client's IP address. It is set to 0 because I will use the static IP address of the host IP running Docker.
xdebug.remote_connect_back=0
#default xdebug 2 port
xdebug.remote_port=9000
#static IP address of the host machine from docker container for OsX and Windows use host.docker.internal
xdebug.remote_host=172.17.0.1

To check if xdebug is configured correctly with PHP, run the command inside the container where the PHP instance is running.

Php –info | grep xdebug

You should get a similar response:

Xdebug configuration details in PHP info

Don’t forget to restart the docker container after making changes in your local xdebug.ini file.

Configuring Xdebug on PhpStorm

Open PhpStorm and go to the menu and open the Settings dialog. In the Settings dialog, choose PHP on the left list. On the right part of the dialog, you will see PHP project settings.

PHP settings dialog

Setting up PHP CLI interpreter

To configure the CLI interpreter, press  (three dots) on the right side of the CLI interpreter line.

In the CLI interpreters dialog, click on + in the upper left corner and choose to set PHP interpreter from Docker.

We need to set the interpreter from our docker-compose configuration file. The first step is creating a Docker connection. If you don’t have a pre-filled Docker server, click the NEW… button in the upper right corner.

Remote PHP interpreter configuration dialog

Name the docker connection as you wish, select Unix socket if you use Linux as your OS, and press OK.

 Docker connection configuration dialog

When you return to the previous interpreter dialog, you must set a local path to the docker-compose.yml file. When you set the docker-compose path, the Service selector will be filled with the services available in your docker-compose config file.

Remote PHP interpreter configuration dialog with service selected

Please choose your PHP/web service (the one with a PHP instance), so IDE can read Xdebug configuration from the container. If your PHP path differs from the default one, you can change it in the PHP interpreter path section. When you are done, click on the OK button.

PHP interpreter dialog will appear.

PHP CLI interpreter configuration dialog

The Xdebug version should be automatically detected. If you don’t see it, click on the refresh button.

Setting up path mapping and server configuration

What is path mapping?

Path mapping will tell Xdebug the location/path of our project files in the Docker container or the remote server if we use Xdebug for remote debugging.

If we set a breakpoint and run the PHP script without setting proper path mapping, IDE will display an error with the message that path mapping is missing. This is because we are running our project in a docker container, which probably has a different path than our local project.

Xdebug – missing server path mapping configuration

I usually set the name of the server in the PHP Docker service environment configuration, as if you do not set it, the name of the host in the Xdebug connection will, by default, be “localhost.” Defining serverName in configuration will help you differentiate projects if you are working on two different projects at the same time.

Environment:
PHP_IDE_CONFIG: 'serverName=docker_symfony'
XDEBUG_CONFIG: 'idekey=PHPSTORM'

Docker-compose.yml PHP service environment configuration 

To set server configuration, we can click on the error link or open Settings -> PHP -> Servers. To define server configuration, click on the + button and set the name of the path mapping configuration. 

PHP/Servers settings dialog

In this example, I’m using docker_symfony. I set the same name as the configuration and host names. By default, the port is set to 80. Change the debugger, if it is not automatically charged, to Xdebug. Below you will see the “Project files” mapping setting.  On the left side will be displayed the local path of the project files. On the right side, I need to set the path inside the Docker container.

You can find the path inside the docker-compose.yml file under the PHP service volume.

volumes:
     - '.:/app'

Save your changes. Now you are ready to start debugging. 

 Server path mapping configuration dialog

PHP Debug configuration interface

A short explanation of PhpStorm configuration interface options for debugging:

  • External connections
    1. Ignore external connections through unregistered server configurations
      • Suppose we set a custom server configuration name, as mentioned before. In that case, we can check this option to ignore other debugging requests from other projects open inside another instance of PhpStorm IDE.
    2. Break at the first line in PHP scripts
      • Helpful to test if the debugger is configured correctly. It will set the breakpoint on the first line in the index.php file.
    3. Max. simultaneous connections
      • Limits the number of debugging connections to IDE.
  • Xdebug
    1. Debug port
      • Sets the port, which will be used to listen to incoming debugging connection requests.
    2. Can accept the external connection
      • Enables/disables debug connection listener.

PHP / Debug configuration dialog

Step-by-step debugging

Setting breakpoints

To create a breakpoint, you have to click on the bar with the row numbers, and a red circle will appear. Clicking again on the same line number will remove the breakpoint.

Breakpoint example

To stop the program in the loop (for, while) or callback methods, we need to add a breakpoint inside them. Otherwise “step over” button will not enter into the loop/method.

Additional breakpoint options

Right-clicking on the breakpoint will give you additional options:

Breakpoint options

Using conditional breakpoints

To create a conditional breakpoint we need to add a condition that must be met to stop program execution on that breakpoint.

Debugging interface

 Debugging interface

Example:

IDE will follow the code by the execution priority. First, the getEmail method will be executed.

Second, the IDE will get to validateEmailDomain method after $login->getEmail() is executed.

On the left side of the debugging interface, you will see the list of scripts accessed during the program run. You can select each script and switch to each script code and see which was executed before the current breakpoint.

On the current break step, you can see active variables in the current script/class/method in the middle of the interface.

You will see the variables/code watchlist on the right side of the interface.  Press the + button to add a variable or code to execute or  to remove it from the watchlist. When adding variables or code to the watchlist, you don’t need to add “; at the end of the line.

Conclusion

I hope this has been a good introduction to how powerful Xdebug is. It is a valuable tool and a huge time saver. Xdebug can make your everyday development work much more user-friendly and less mysterious. I couldn’t imagine developing without it, and I hope you will also start using it in your work.


Leave a Reply

Your email address will not be published. Required fields are marked *