DEV Community

Jack Miras
Jack Miras

Posted on • Updated on

Xdebug in PhpStorm with Docker

In my last post, I talked about how to configure Xdebug in VSCode with Docker. Now, I would like to share how we can build upon our previous Dockerfile in such a way that Xdebug can run directly from Docker and also connect it with PhpStorm.

By choosing this approach, we substantially reduce the amount of setup that each team member has to do on their machine to get the project up and running, which means that we can start writing code faster.

So, why is this so important? Recent research from JetBrains shows that 62% of PHP developers debug their code using var_dump(), die(), dd(), and dump().  From my perspective, there is nothing wrong with that. Even if you do it by choice and not because you lack knowledge.

I'm included in the 62% of developers who debug their code with auxiliary functions instead of using a full-featured debug solution such as Xdebug. I'm a heavy Neovim user, and I didn't adapt quite well to using Neovim with Xdebug; to me, it is just easier and faster to use my code snippets around the dd() function.

But occasionally, I catch myself in situations where it would be faster to jump into PhpStorm and just use Xdebug, especially when I'm working with other people who aren't familiar with Vim or Neovim.

Content

Xdebug config file

Before jumping into PhpStorm, first we have to clear up a few things about Xdebug to fully grasp the changes we’re going to make to the IDE. The information was first introduced on the topic of the command directive in a previous post. You will notice that at some point a xdebug.ini file gets copied from a local .docker folder into /etc/php8/conf.d/50_xdebug.ini at the container.

Even though the content of the file got shown, I intentionally didn't explain its content so that we could explore the debugging topic all at once, going all the way from configuring Xdebug to using it with an IDE.

Down below, we have the same Xdebug config file from the previous post, placed at .docker/xdebug.ini on the root of our Laravel project. Each line of code will be explained further, but in case you want to know every configuration that you can add in this file, check the Xdebug documentation.

zend_extension=xdebug.so
xdebug.mode=develop,coverage,debug,profile
xdebug.idekey=docker
xdebug.start_with_request=yes
xdebug.log=/dev/stdout
xdebug.log_level=0
xdebug.client_port=9003
xdebug.client_host=<YOUR_COMPUTER_IP>
Enter fullscreen mode Exit fullscreen mode

Explaining xdebug.ini

  • zend_extension=xdebug.so

A Zend extension hooks into “lower-level” languages; 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 get enabled; according to the documentation, the following values will get 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 the 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 gets executed. For example, xdebug.mode=trace and xdebug.start_with_request=yes, start a function trace for the whole request.

  • xdebug.log=/dev/stdout

Configure Xdebug's log file, but in this case, we are redirecting the log content to the default stdout of our container.

In case you don't want to see these logs you can comment out this line of your .docker/xdebug.ini file by changing the line to ;xdebug.log=/dev/stdout.

  • xdebug.log_level=0

Configures which logging messages should be added to the log file. In this case, we are instructing Xdebug to log only errors in the configuration. If you want to see more information, you can use level 7 for log info or level 10 for log debug.

  • 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.client_host=<YOUR_COMPUTER_IP>

Configures the IP address or hostname to which Xdebug will attempt to connect when initiating a debugging connection. This address should be the address of the machine where your IDE or debugging client is listening for incoming debugging connections.

Down below, you can see how to get your IP address correctly in the main OS the developers use. In case you are using a different OS, the commands may serve as a base to try to extrapolate a solution for your use case.

macOS:

ipconfig getifaddr en0
Enter fullscreen mode Exit fullscreen mode

Windows with WSL:

grep nameserver /etc/resolv.conf | cut -d ' ' -f2
Enter fullscreen mode Exit fullscreen mode

Linux (Debian-based distros):

hostname -I | cut -d ' ' -f1
Enter fullscreen mode Exit fullscreen mode

Once you have correctly found your IP address, you can place it into xdebug.client_host as mentioned before, and that will leave you with a directive looking similar to this: xdebug.client_host=192.168.0.158.

In summary, you've instructed Xdebug to start with a request and try to send the debug events to the host with the IP 192.168.0.158 on port 9003. Since the IP represents your computer, when configuring PhpStorm to connect to Xdebug, the configuration will be extremely similar to when connecting to localhost.

PhpStorm

As you may already know, PhpStorm is a proprietary, cross-platform IDE for PHP, built by the Czech Republic-based company JetBrains. PhpStorm provides an editor for PHP, HTML, and JavaScript with on-the-fly code analysis, error prevention, and automated refactorings for PHP and JavaScript code.

With that being said, you may be wondering: “What do we need to have PhpStorm with all the aspects of an IDE with full-featured debugging”?

For starters, we need to check if the IDE can properly connect with Docker:

check-docker-connection

Thereafter, we have to configure a PHP server. This can be done by going to Settings > PHP > Servers, then clicking on the plus sign, as the following screenshot shows:

php-servers00

Once you click the plus sign, a form will open, where the Name, Host, Port, and Absolute path of the server have to be filled in:

php-servers01

Notice that the Port matches the port from our previsouly built docker-compose.yml and the Absolute path on the server matches the workdir from our previously built Dockerfile.

Now, that the server has been created, we can move to the debug configuration. Let's start by clicking on the More Actions button in the main window, as the next screenshot shows:

run-debug-configurations00

Then, click on the Edit… option to open the Run/Debug Configurations window:

run-debug-configurations01

Subsequently, click into Add New Configuration  > PHP Remote Debug as the screenshot down below shows:

run-debug-configurations00

Next, a form will open, and there, fill the Name with your Remote Debug configuration; next, check the Filter debug connection by IDE key option and then select the Server previously created; and finally, fill the IDE key (session id) with the same value that got used at the xdebug.idekey directive at our .docker/xdebug.ini. More details are in the illustration below:

run-debug-configurations03

As a result of the previous steps, the remote debug configuration got finished, and PhpStorm can now start listening for PHP debug connections. Click on the indicated button, as shown:

start-listening-to-php-debug-connections

And then, as a final step, click the debug button. Once the debug is running, you can trigger a request through Postman or your tests, and PhpStorm will intercept the event and stop at the first breaking point found.

debug-docker


Now, Xdebug is finally configured in your PhpStorm, and you can enjoy a more robust debugging tool with the potential to speed up your entire workflow.

Happy coding!

Top comments (10)

Collapse
 
nuryagdym profile image
nuryagdym

Thanks for article!
I want to add some notes.

  1. I set my host address like this "xdebug.client_host=host.docker.internal" in xdebug.ini
  2. xdebug.mode=develop,coverage,debug,profile in this config "profile" mode made debugging extremely slow.
  3. For debugging CLI commands, I additionally set this environment variables in PHP container env:
    1. PHP_IDE_CONFIG="serverName=Docker-laravel_scaffold".
    2. XDEBUG_TRIGGER=docker - the same value you set in xdebug.ini for xdebug.trigger_value
Collapse
 
jackmiras profile image
Jack Miras • Edited

@nuryagdym how are you doing?

Thanks for adding the notes, I really appreciate it!

I just would like to leave it an observation about setting xdebug.client_host=host.docker.internal... Last time I've checked this didn't work for all OS (Linux, Mac, and Windows) while setting the IP works for the three of them.

For anyone else reading this comment, if your OS works by setting the client host this way, I recommend that you do it because it will save you from having to update your IP address from time to time.

Also, could you to share what have you done about the xdebug.mode=profile? Have you removed it to avoid slowness? I'm asking because other people reading the article and comments may run in the same problem.

Once again, thanks for adding the notes.

Collapse
 
nuryagdym profile image
nuryagdym

I am good thank, hope you are well also :).
xdebug.client_host=host.docker.internal does work on my Mac.

I removed profile mode from xdebug.mode. I had a heavy CLI command which runs hours, and profile mode was creating cacheGrind log files which become huge (millions of rows).

Collapse
 
jonpontet profile image
JP

Yes! Thank you!
I couldn't get Xdebug 3 working with Docker + WordPress on Mac. It was adding the PHP Remote Debug configuration and using xdebug.idekey that made the difference.

Collapse
 
lebru profile image
le-bru

Hi,
thanks for that tutorial. Sort of got it to run.

However, the moment I tell PHP Storm to listen for debugging connections, any request to my application would run into a timeout.
Only if I tell PHPStorm to listen for debugging connections, the request will be processed, and also only by clicking on "Resume Program" in the Debug window.

Is that intended behavior or is there something wrong with my setup?

My understanding so far was, that program execution should only be interrupted if there are breakpoints set.

Collapse
 
jackmiras profile image
Jack Miras • Edited

Hello @lebru,

I didn't experience this issue, but In case you didn't resolve this issue yet, please mail me at jackmiras@gmail.com with more details and prints and/or videos about the problem… I'll reproduce it as soon as I can.

Collapse
 
andythedandy profile image
Andy Eberle-Bannert

Thanks!

"Notice that the Port matches the port from our previsouly built docker-compose.yml" <- Which docker-compose.yml?

Is there something like

ports:
  - 8000:9003
Enter fullscreen mode Exit fullscreen mode

in there?

Collapse
 
jackmiras profile image
Jack Miras

Hello @andythedandy, how are you doing?

Thanks for quoting this part of the post, it was, in fact, missing external links pointing to the other two posts that serve as base to this one.

Talking about the PHP > Servers configuration, we are pointing to port 8000 because we are connecting to the service in our docker-compose stack that has PHP ready to go.

As you will notice, this service which is called app gets built based on a Dockerfile, also explained in a previous post.

Both the post where I share how do I usually build my Dockerfile and docker-compose.yaml are now linked in the same session that initially got you confused.

In case you've notice anything else in this post or if you have other questions, feel free to reach me out.

Collapse
 
josemiguelq profile image
Jose Miguel

A definitive tutorial and explanation

Collapse
 
tieutantan profile image
Tran Ngoc Tan

thank you, I need your guide