Debugging PHP on Docker with VS Code

Author by Maros
10 minutes
Debugging PHP on Docker with VS Code

Welcome to the third article of PHP on Docker. In the previous article, we learned how to create two connected containers with php and nginx with the help of Docker compose, and also talked about different environments where your software needs to work.

In this article, we'll continue our discussion about development environments -more specifically, we will talk about debugging with the help of PHP Tools inside Visual Studio Code. We will be using our php+nginx setup from the last article and you can find all the source codes on github

Xdebug

Xdebug is a debugging extension for PHP. Debugging is basically a way to slow down the execution of code, to the point you are able to think about what's going on. On the picture below, you can see a very simplified pipeline of execution: that's what we're going to build in this tutorial.

Xdebug diagram

After a request to our docker container, Xdebug will initiate a connection with our IDE. In our case, we will be using Visual Studio Code with PHP Tools. Xdebug is using DBGP protocol for this communication.

Dockerfiles

We'll be using PHP with Nginx, just like in our last article. Let's start by modifying our PHP Dockerfile:

FROM php:fpm
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug

Instead of using the Alpine version of php-fpm image, we are using the default php-fpm image with Debian for simplicity. Xdebug depends on some libraries, which would have to be installed manually, if we would use Alpine. In Debian, they are present without any work. The only thing we have to install is Xdebug, and then enable it with the docker-php-ext-enable helper command. You can find out more about this command here.

You can also add copying of custom php.ini file in the end of our Dockerfile, but we can setup everything we will need, with the use of Environment variables in our docker-compose.yml.

Nginx

As I said before, we will be using Nginx. It's Dockerfile and settings did not change. You can see the Dockerfile here:

FROM nginx:alpine
COPY nginx/default.conf /etc/nginx/conf.d

and default.conf here:

server {
    listen 0.0.0.0:80;

    root /var/www/html;

    location / {
        index index.php index.html;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }

    error_log /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
}

Docker-compose.yml

Let's take a look at our docker-compose.yml for its use with Xdebug. The complete configuration looks like this:

version: "3"
services:
  nginx:
    build:
      context: .
      dockerfile: nginx/Dockerfile
    ports: 
      - "8080:80"
    networks:
      - internal
    volumes:
      - ./data/:/var/www/html
  php:
    build:
      context: .
      dockerfile: php/Dockerfile
    networks:
      - internal
    environment:
      XDEBUG_CONFIG: remote_host=host.docker.internal remote_port=9000 remote_enable=1
    volumes:
      - ./data/:/var/www/html
networks:
  internal:
    driver: bridge

It's basically the same configuration for the development environment with PHP and Nginx from the last article, but we have added a few environment variables for the Xdebug configuration:

  • remote_host: This is the address which Xdebug will try to contact using DGBP protocol when our php container receives a request to process a php script. We are using a special value host.docker.internal which will be automatically replaced with the IP address of Docker Host. You can find more special environment variables for Docker Compose here.

  • remote_port: This is the port which Xdebug will try to connect to. The port 9000 is default and we specify it here only for completeness.

  • remote_enable: We want to enable this, because we will be debugging from a different machine.

With simple phpinfo(); in our index.php inside a data folder, we can try to compose our containers. Right click on docker-compose.yml and click compose up.

Compose Up

If everything is setup correctly, you should be able to see Xdebug section in phpinfo inside a browser.

Xdebug extension

Path mappings and launch.json

Debugging will still not work for us yet. We need to configure it with Visual Studio Code. Switch to the Debug section on the left panel in Visual Studio Code and click Configure or Fix 'launch.json' button.

Configure or Fix 'launch.json'

If you already have launch.json created, instead of "No Configurations", you will see "Listen for Xdebug" and Open launch.json button.

Open 'launch.json'

PathMappings

The last thing we need to debug our PHP code with Visual Studio Code and PHP Tools are Path Mappings. It specifies, where are the files we will be debugging. Add another entry to "Listen for Xdebug" section in launch.json, so it looks similar to this:

{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9000,
"pathMappings": {
"/var/www/html": "${workspaceFolder}\\3 - PHP and Xdebug\\data"
},

We have specified that everything located in /var/www/html on our docker container should be looked for in ${workspaceFolder}\3 - PHP and Xdebug\data. Modify it depending on your folder structure if you need. ${workspaceFolder} is a special variable from Visual Studio Code and it is replaced with a folder you opened by using the Open folder menu option. You can find more special variables here.

Debugging

Now, you should be able to debug your PHP running on Docker in Visual Studio Code.

Open index.php, add a [breakpoint]() and click the Listen for Xdebug button. Visual Studio Code should start listening for the Xdebug connection and it should look like the picture below.

Visual Studio Code Listening

When you make a request with a browser, the execution should be halted. The line where the code was halted should be highlighted like this:

Visual Studio Code Breakpoint

Now you should be able to see local variables, callstack and other typical debugging features.

Summary

In this article, we took our multi-container setup with php and nginx from the last article and added debugging capabilities with Xdebug. With PHP Tools we have a complete debugging experience for PHP inside Visual Studio Code.

Other articles about debugging