gwomacks/php-debug

Context variables empty

Opened this issue · 1 comments

The debugger is enabled and listening, and it stops on my breakpoints, but the three sections (locals, superglobals, user defined constants) are all empty, leaving me unable to actually debug anything. Is this a pathmap problem?

acran commented

I was able to reproduce this and find the root cause: if any value/attribute in the context is an instance of an anonymous class the stack trace panel and context panel won't update (i.e. stay empty or still display the values of the previous step).

The reason for this is that PHP puts a null byte in the generated name of the anonymous class which is encoded as � by xdebug in its XML messages. Trying to parse this XML leads to an exception, since � (U+0000) is not a valid XML entity.

A small example for reproduction:

<?php

$number = 5;
$greeting = 'Hello';
$array = [$number, $greeting];

$anonClass = new class {}; // php-debug breaks after this line

$number = 10;
$greeting = 'Good Day';
$array = [$number, $greeting];

var_dump($number);
var_dump($greeting);
var_dump($array);
var_dump($anonClass);

Breaking and stepping up until line 7 ($anonClass = new class {};) works fine but anything after that won't update the stack trace and context panels anymore.

The offending XML produced by xdebug for this is then:

<property name="$anonClass" fullname="$anonClass" type="object" classname="class@anonymous&#0;/app/public/debug.php:7$583b" children="0" numchildren="0" page="0" pagesize="32"></property>

Note the illegal &#0; entity in the classname.

This is then parsed by xml2js.parseString which ultimately uses sax-js and in its parseEntity function the null byte then causes an error.

I'm not sure how to address this issue now, since it is a weird combination of upstream issues:

  • xdebug produces invalid XML by encoding the null byte - but it only writes the class name as produced by PHP
  • xml2js / sax fail to parse the produced XML - although this seems unintentional (removing leading 0s also removes the actual 0 value) it is eventually correct