April 2, 2020

539 words 3 mins read

Debugging Drupal in Lando using (Neo)vim and Vdebug

Debugging Drupal in Lando using (Neo)vim and Vdebug

With the introduction of OOP on Drupal 8, it has become a bit difficult for me to track how Drupal processes each request. Most of the time, you’ll be dealing with different objects, track down which class were instantiated and methods that were called, and inspect the variables.

Tools

So what are the tools that I am using? I’ve been a long time user of vim and recently just switched to Neovim. For development environment, I mostly jump between different methods for building Drupal but recently have been using Lando.

Lando

For the configuration, simply setting xdebug to true so that Lando would enable xdebug in the environment:

name: drupal
recipe: drupal8

services:
  appserver:
    webroot: web
    xdebug: true
    config:
      php: config/php.ini

For config/php.ini, I simply followed the one from setting up vscode:

[PHP]

; Xdebug
xdebug.max_nesting_level = 256
xdebug.show_exception_trace = 0
xdebug.collect_params = 0
; 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.log

(Neo)vim

For (Neo)vim, Vdebug seems to be the only option for using Xdebug in PHP. A minimal configuration can be:

call plug#begin(stdpath('data') . '/plugged')
Plug 'vim-vdebug/vdebug'
call plug#end()

if !exists('g:vdebug_options')
  let g:vdebug_options = {}
endif

let g:vdebug_options.path_maps = {
    \  '/app' : getcwd(),
\ }

let g:vdebug_options.break_on_open = 0
let g:vdebug_options.watch_window_style = 'compact'

if !exists('g:vdebug_features')
  let g:vdebug_features = {}
endif

let g:vdebug_features.max_children = 128

vdebug_options.path_maps sets the paths so that it works with Lando. Due to the getcwd() value, you’ll need to make sure that before starting (Neo)vim, you’re current working directory would be your workspace i.e. whatever is mounted on ‘/app’ inside Lando.

vdebug_features.max_children allows inspecting variables from Drupal most of the time.

For other options, they can be found on :h Vdebug.

Debugging

Consider the scenario where you are viewing a node and wanted to debug the method \Drupal\node\Entity\Node::getType(). To start debugging, open the file core/modules/node/src/Entity/Node.php and set a breakpoint using F10, start the debugger using F5, and finally visit a single node.

I’m not entirely sure of the actual definitions for step debugging although in my own words, I can probably explain them like these:

  • Step over: continue to the next line in the source.
  • Step into: if the line calls a certain function/method, then go over to that function/method where you can then continue debugging.
  • Step out: skip the remaining lines and proceed to the next step.

Bindings

From the configuration above, it mostly just relies on the default bindings (:h VdebugKeys):

let g:vdebug_keymap = {
\    "run" : "<F5>",
\    "run_to_cursor" : "<F9>",
\    "step_over" : "<F2>",
\    "step_into" : "<F3>",
\    "step_out" : "<F4>",
\    "close" : "<F6>",
\    "detach" : "<F7>",
\    "set_breakpoint" : "<F10>",
\    "get_context" : "<F11>",
\    "eval_under_cursor" : "<F12>",
\    "eval_visual" : "<Leader>e",
\}

User interface

Vdebug UI

The explanation for each window can be found at :h VdebugUI. I find the “Watch” window very helpful since I can inspect the different variables with their context. Pressing Enter on a variable would expand/collapse their trees.

So far, I think these are the basic things to debugging with (Neo)vim using Vdebug. Vdebug has a lot of other features such as evaluating although I haven’t gone much further yet.