Using Lando with VSCode

Visual Studio Codeopen in new window is a great open source editor for programming. Debugging PHP applications with it can be easy too.

This is a basic setup to help you in this task.

Getting Started

Enable Xdebug by adding some lines to your Lando recipe.

name: mywebsite
recipe: drupal9
services:
  appserver:
    webroot: web
    xdebug: debug
    config:
      php: .vscode/php.ini

Create a custom php.ini file (place it wherever you want - we use .vscode folder because we find it convenient).

touch .vscode/php.ini
code .vscode/php.ini

PHP 7.2+ uses xdebug 3 and needs the following php.ini configuration settings:

[PHP]

; Xdebug
xdebug.max_nesting_level = 256
xdebug.show_exception_trace = 0
xdebug.collect_params = 0
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_host = ${LANDO_HOST_IP}
; xdebug.log = /tmp/xdebug.log

; Remote settings
xdebug.remote_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_host = ${LANDO_HOST_IP}
; xdebug.remote_connect_back = 1
; xdebug.remote_log = /tmp/xdebug_remote.log

PHP 7.1 and earlier uses xdebug 2 and needs slightly different configuration in php.ini:

[PHP]

; Xdebug
xdebug.max_nesting_level = 256
xdebug.show_exception_trace = 0
xdebug.collect_params = 0
; xdebug.log = /tmp/xdebug.log
; Extra custom Xdebug setting for debug to work in VSCode.
xdebug.remote_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_host = ${LANDO_HOST_IP}
; xdebug.remote_connect_back = 1
; xdebug.remote_log = /tmp/xdebug_remote.log

Rebuild your environment.

lando rebuild -y

Finally, create a custom launch.json file in your workspace in order to map paths so that XDebug works correctly.

touch .vscode/launch.json
code .vscode/launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Listen for XDebug",
      "type": "php",
      "request": "launch",
      "port": 9003,
      "log": false,
      "pathMappings": {
        "/app/": "${workspaceFolder}/",
      }
    }
  ]
}

Note: PHP 7.1 and earlier uses xdebug 2 which uses port 9000, so change the port number above accordingly.

Done!

You can now click start debugging (type F5 or click on the icon in the left sidebar).

Advanced Setup

Optionally for better performance you can easily toggle Xdebug on and off with some custom tooling commands.

If you're using Apache, add this to your .lando.yml:

services:
  appserver:
    overrides:
      environment:
        XDEBUG_MODE:
tooling:
  xdebug-on:
    service: appserver
    description: Enable xdebug for Apache.
    cmd: rm -f /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && docker-php-ext-enable xdebug && /etc/init.d/apache2 reload && echo "Xdebug enabled"
    user: root

  xdebug-off:
    service: appserver
    description: Disable xdebug for Apache.
    cmd: rm -f /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && /etc/init.d/apache2 reload && echo "Xdebug disabled"
    user: root

If you're using Nginx, add this to your .lando.yml:

services:
  appserver:
    overrides:
      environment:
        XDEBUG_MODE:
tooling:
  xdebug-on:
    service: appserver
    description: Enable xdebug for nginx.
    cmd: docker-php-ext-enable xdebug && pkill -o -USR2 php-fpm && echo "Enabling xdebug enabled"
    user: root

  xdebug-off:
    service: appserver
    description: Disable xdebug for nginx.
    cmd: rm -f /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini && pkill -o -USR2 php-fpm && echo "Xdebug disabled"
    user: root

Now you can turn Xdebug on or off with lando xdebug-on and lando xdebug-off. If you want Xdebug off by default, set xdebug:false in your appserver config:

name: mywebsite
recipe: drupal8
services:
  appserver:
    webroot: web
    xdebug: false
    config:
      php: .vscode/php.ini

Debugging PhpUnit

Debugging PhpUnit tests in VSCode requires a little more setup, but Lando helps to make it easier.

First, you need to have VSCode listen for debugging on 2 separate ports, because PhpUnit runs in one process and the tests themselves in another, and VSCode's Xdebug extension currently struggles with this. You accomplish this by have a launch.json that looks like this:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Listen for XDebug",
      "type": "php",
      "request": "launch",
      "port": 9003,
      "log": true,
      "pathMappings": {
        "/app/": "${workspaceFolder}/",
      }
    },
    {
      "name": "PhpUnit dummy",
      "type": "php",
      "request": "launch",
      "port": 9001,
    }
  ],
  "compounds": [
    {
        "name": "PhpUnit",
        "configurations": ["Listen for XDebug", "PhpUnit dummy"]
    }
       ]
}

Next add some custom tooling to your .lando.yml file, that provides a command to run PhpUnit in a way points the main PhpUnit process to the PhpUnit dummy debugger we just added. (The syntax here assumes a project-specific installation of PhpUnit, not a global one).

tooling:
  phpunitdebug:
    service: appserver
    cmd: php -d xdebug.remote_port=9003 vendor/bin/phpunit

Note: PHP 7.1 and earlier uses xdebug 2 which uses port 9000, so change the port number above accordinly.

Now to run debug a PhpUnit test, do the following:

  1. Select the compound "PhpUnit" as your debugger in VSCode's UI, and start it.
  2. Make sure you untick "Everything" in the breakpoints section of the UI, or it will break every time PhpUnit throws an exception, even if it's properly caught by PhpUnit.
  3. Add a breakpoint in your code that is being tested.
  4. On your command line run PhpUnit with something like lando phpunitdebug --filter=testMyTestMethodName (this example is of running a single test method, actually you can add any phpunit options you like at the end).

Known issues

Xdebug session doesn't start

If Xdebug session doesn't start, dig into the log file inside the application.

Uncomment some lines in your php.ini file:

xdebug.log = /tmp/xdebug.log
xdebug.remote_log = /tmp/xdebug_remote.log

Rebuild your app:

lando rebuild -y

Enter the app with lando ssh and open the debug file (/tmp/xdebug.log).

Path to the debug file is configured in your custom php.ini.

Now open your app in a browser and see what's being logged.

lando ssh
tail -f /tmp/xdebug.log
# Open your browser and refresh the app

Xdebug says "timeout trying to connect to XX.XX.XX:9003

Double-check your host machine allow connection on its port 9003.

This is how you can open a specific port on a Debian/Ubuntu:

sudo iptables -A INPUT -p tcp -d 0/0 -s 0/0 --dport 9003 -j ACCEPT

Read More