Skip to content

Debug PHP CLI

Debug a PHP script that starts, does its work and exits.

Prerequisites

  • php-dbgp-adapter on PATH:
make build
export PATH="$PWD/target/debug:$PATH"
  • Xdebug installed in the PHP that will run the script

Xdebug settings

xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=localhost
xdebug.client_port=9003

localhost because PHP runs on the same machine here. In a container it would be host.docker.internal.

Config

version = 1
default = "cli"

[profiles.cli]
adapter = "php"
program = "."

[profiles.cli.launch_arguments]
sessionMode = "cli"
port = 9003

sessionMode = "cli" is the important part: it says a one-shot process is coming.

Run — order matters

Start the listener first, then the script

A one-shot process can finish before Xdebug ever connects if the adapter is not already listening.

  1. Start the session:
bugsaur gui --project . --break src/import.php:20
  1. Then run the script:
php src/import.php

What should happen

Xdebug connects at the start of the request, the adapter accepts it, and the script stops at line 20.

Triggering per run instead of always

start_with_request=yes makes every PHP invocation try to connect, which is noisy on a machine where you also run other scripts. The alternative is trigger:

xdebug.start_with_request=trigger

Then only runs that carry the trigger are debugged:

XDEBUG_TRIGGER=1 php src/import.php

No cwd, env or args

The adapter launches nothing, so those profile fields do not apply to PHP. Pass arguments and environment on the command line that starts PHP:

APP_ENV=dev php src/import.php --dry-run

When it does not work

Symptom Fix
The script runs, nothing stops the listener was not up yet — start the session first
Nothing ever connects check xdebug.mode=debug; verify with php -i \| grep xdebug
Port already in use another project holds 9003 — give this one a different port
Stops without source you are running in a container after all — see Debug PHP in Docker