Configuring xDebug with Laravel and VS Code

Published: Posted by Patrick Henninger

Why step debugging?

When writing software it does not matter how well the code is written or how cautious we are - there will inevitably be some bugs along the way. The proccess of solving a bug in all cases does at least require the following information:

  • What is the error?
  • Where did the error occur?

Depending on how familiar we are with the codebase at hand these questions can be answered rather fast, but there are times when we need additional feedback - expicially when we do not exactly know where the execution of our codebase is breaking due to bad error handling or improper capsulation hiding the error and stack trace.

Traditionally we would simply add some debug/log output to the suspected areas in the code and watch out for these while running it but there are several drawbacks with this method: it does require to modify (and possibly rebuild) our software as well as it does require implementation specific code to generate these outputs. The mentioned drawbacks can make debugging that way very tedious and unneccessarily time consuming. Luckily there is a way that does allow us to basically look at our code and data at runtime and go throught it line by line: step debugging.

The most known extension to provide step debugging for PHP and applications based on the Laravel framework is xDebug. The PHP extension has a long history of complicated configuration files and refusing to work but this has changed with the third major release of the extension. The installation of xDebug now basically requires zero configuration by using environment variables! In this post i am going to explain how you can setup xDebug for VS Code in regards to Laravel Sail or your own development container by guiding you throught the following steps:

  1. Install xDebug PHP extension
  2. Configure xDebug
  3. Add a xDebug browser extension
  4. Configure VS Code for xDebug

xDebug installation (Docker)

When using Laravel's first party Docker environment, Laravel Sail, xDebug does already come with it installed by default so you can skip this step - otherwise you can follow these steps to add xDebug to your PHP development container. This setup is based on Laravel Sail as it does provide an amazing example on how to integrate the extension.

First you will have to install the xDebug extension in your Dockerfile with the following command replacing X.X with your PHP version:

RUN apt-get update && apt-get install -y phpX.X-xdebug

Next it is important to configure the remote debugging host - in the case of Docker this is the Docker host. To do so from within a container you can use the host.docker.internal host which will resolve the host Docker host. In order to configure this as a default we are going to add some entries to our docker-compose environment section. These will allow us to use the environment file to configure the xDebug extension as well as to define default values:

environment:
    ...
    XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
    XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'

Important: On linux host.docker.internal is only supported on the latest versions of docker engine! In order to use it you will have to add the host to your docker-compose.yml extra_hosts section using the host-gateway feature like so:

extra_hosts:
    host.docker.internal: host-gateway

xDebug configuration

As mentioned in the previous step Laravel Sail provides an outstanding example on how to integrate xDebug into a dockerized development environment by passing the required environment variables to configure the extension to the container directly from the applications .env file - preventing a rebuild of the docker image re-configuring xDebug. Let's take a look at these environment variables:

  • XDEBUG_MODE: This variable controls which xDebug features are enabled. Set this to debug,develop for xDebug step debugging to work. You can find a full list of possible values in the offical documentation.
  • XDEBUG_CONFIG: This variable can be used to set ini config options with OPTION=VALUE

Browser extension

As we do not want to constantly trigger debugging we are going to use a browser extension to add the neccessary headers to each outgoing request to activate xDebug and initiate step debugging. You can use one of the following extensions:

In order to start debugging you will have to set the extension into debug mode.

Visual Studio Code configuration

Once xDebug is installed and configured in the container as well as the browser extension has been installed we can proceed to configure VS Code for step debugging with xDebug. It is important to precisely follow the following steps as step debugging with PHP will not work out of the box in VS Code.

Extension

First we are going to install the PHP Debug extension provided by xDebug for VS Code. To do so navigate to the extensions tab in your VS Code, search for PHP Debug and install the extension.

Workspace

Next you will have to create a workspace configuration file - this is required as VS Code can not resolve paths reported by xDebug. To do so in VS Code go/navigate to the File tab in the upper left hand corner and select Save workspace as. Save the workspace file and make sure that VS Code has automatically opened it by checking for workspace in the window title.

launch.json

Once the extension has been installed and the workspace set up successfully we can procceed to create our launch.json file - this will include the necessary configuration for VS Code to communicate with xDebug. To do so simply navigate to the debugging tab and click on create a launch.json file and select PHP in the following dialog. This should create a launch.json in the .vscode/ directory.

Edit this file and replace all entries with the following one:

{
    "log": true,
    "name": "Listen for xDebug",
    "type": "php",
    "request": "launch",
    "port": 9003,
    "pathMappings": {
        "/var/www/html": "${workspaceRoot}",
    }
}

Note the /var/www/html in our launch.json configuration: this is the path where your codebase has been mounted inside the docker container. You will have to adjust this to your project if you are not using Laravel Sail or diverging from their directory structure on purpose.

You should now be able to debug your application by navigating to it in your browser. To see if it does work, add a breakpoint at the very first line of code in your public/index.php by clicking left of the line number - a red circle should appear once a breakpoint has been set.