View Issue Details

IDProjectCategoryView StatusLast Update
0001644XdebugRemote Debuggingpublic2019-03-05 13:27
Reporterdv-dsAssigned Toderick 
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionno change required 
Product Version2.7.0RC2 
Target VersionFixed in Version 
Summary0001644: Cannot evaluate local variable in function
DescriptionIt appears that at least under certain circumstances, it is not possible to evaluate a variable local to a function.
Steps To Reproduce<?php

function foobar() {
    $a = 42;
    echo $a; // Place breakpoint here
}

foobar();

// 1. Attempt to evaluate $a by hovering over it (same line as breakpoint), this yields no result. It is also not listed as a local.
// 2. Attempt to evaluate $a in the console. This yields null.
Additional InformationAnnotated Xdebug log attached.

Setup:
- Visual Studio Code, 1.31.1
- Apache 2.4.37 (Homebrew)
- PHP 7.3.1 (Homebrew)

I also found an issue that may or may not be related, where evaluating a function argument is only possible when using the console. Would you like a separate bug for this?
TagsNo tags attached.
Operating SystemmacOS
PHP Version7.3.0-7.3.1

Activities

dv-ds

2019-03-04 17:13

reporter  

xdebug-log.txt (10,600 bytes)
// Some information replaced with placeholders like "foo.php" and "..."

/* Start and let the breakpoint hit */

[13856] Log opened at 2019-03-04 16:47:22
[13856] I: Connecting to configured address/port: localhost:9000.
[13856] I: Connected to client. :-)
[13856] -> <init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" fileuri="file:///foo.php" language="PHP" xdebug:language_version="7.3.1" protocol_version="1.0" appid="13856"><engine version="2.7.0RC2"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[https://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2019 by Derick Rethans]]></copyright></init>
[13856]
[13856] <- feature_set -i 1 -n max_children -v 256
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="feature_set" transaction_id="1" feature="max_children" success="1"></response>
[13856]
[13856] <- breakpoint_list -i 2
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="2"></response>
[13856]
[13856] <- breakpoint_set -i 3 -t line -f file:///foo.php -n 5
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="3" id="138560004"></response>
[13856]
[13856] <- breakpoint_list -i 4
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="4"><breakpoint type="line" filename="file:///foo.php" lineno="5" state="enabled" hit_count="0" hit_value="0" id="138560004"></breakpoint></response>
[13856]
[13856] <- breakpoint_list -i 5
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_list" transaction_id="5"><breakpoint type="line" filename="file:///foo.php" lineno="5" state="enabled" hit_count="0" hit_value="0" id="138560004"></breakpoint></response>
[13856]
[13856] <- breakpoint_set -i 6 -t exception -x *
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="breakpoint_set" transaction_id="6" id="138560005"></response>
[13856]
[13856] <- run -i 7
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="run" transaction_id="7" status="break" reason="ok"><xdebug:message filename="file:///foo.php" lineno="5"></xdebug:message></response>
[13856]
[13856] <- stack_get -i 8
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stack_get" transaction_id="8"><stack where="foobar" level="0" type="file" filename="file:///foo.php" lineno="5"></stack><stack where="{main}" level="1" type="file" filename="file:///foo.php" lineno="8"></stack></response>
[13856]
[13856] <- context_names -i 9 -d 0
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="context_names" transaction_id="9"><context name="Locals" id="0"></context><context name="Superglobals" id="1"></context><context name="User defined constants" id="2"></context></response>
[13856]
[13856] <- context_get -i 10 -d 0 -c 0
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="context_get" transaction_id="10" context="0"></response>
[13856]

/* Hover over $a (at the same line as the breakpoint) */

[13856] <- context_get -i 11 -d 0 -c 1
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="context_get" transaction_id="11" context="1"><property name="$_COOKIE" fullname="$_COOKIE" type="array" children="0" numchildren="0" page="0" pagesize="256"></property><property name="$_ENV" fullname="$_ENV" type="array" children="0" numchildren="0" page="0" pagesize="256"></property><property name="$_FILES" fullname="$_FILES" type="array" children="0" numchildren="0" page="0" pagesize="256"></property><property name="$_GET" fullname="$_GET" type="array" children="0" numchildren="0" page="0" pagesize="256"></property><property name="$_POST" fullname="$_POST" type="array" children="0" numchildren="0" page="0" pagesize="256"></property><property name="$_REQUEST" fullname="$_REQUEST" type="array" children="0" numchildren="0" page="0" pagesize="256"></property><property name="$_SERVER" fullname="$_SERVER" type="array" children="1" numchildren="35" page="0" pagesize="256"><property name="SCRIPT_URL" fullname="$_SERVER[&quot;SCRIPT_URL&quot;]" type="string" size="1" encoding="base64"><![CDATA[...]]></property><property name="SCRIPT_URI" fullname="$_SERVER[&quot;SCRIPT_URI&quot;]" type="string" size="17" encoding="base64"><![CDATA[...]]></property><property name="APPLICATION_ENV" fullname="$_SERVER[&quot;APPLICATION_ENV&quot;]" type="string" size="5" encoding="base64"><![CDATA[...]]></property><property name="HTTP_HOST" fullname="$_SERVER[&quot;HTTP_HOST&quot;]" type="string" size="9" encoding="base64"><![CDATA[...]]></property><property name="HTTP_CONNECTION" fullname="$_SERVER[&quot;HTTP_CONNECTION&quot;]" type="string" size="10" encoding="base64"><![CDATA[...]]></property><property name="HTTP_CACHE_CONTROL" fullname="$_SERVER[&quot;HTTP_CACHE_CONTROL&quot;]" type="string" size="9" encoding="base64"><![CDATA[...]]></property><property name="HTTP_UPGRADE_INSECURE_REQUESTS" fullname="$_SERVER[&quot;HTTP_UPGRADE_INSECURE_REQUESTS&quot;]" type="string" size="1" encoding="base64"><![CDATA[...]]></property><property name="HTTP_USER_AGENT" fullname="$_SERVER[&quot;HTTP_USER_AGENT&quot;]" type="string" size="121" encoding="base64"><![CDATA[...]]></property><property name="HTTP_DNT" fullname="$_SERVER[&quot;HTTP_DNT&quot;]" type="string" size="1" encoding="base64"><![CDATA[...]]></property><property name="HTTP_ACCEPT" fullname="$_SERVER[&quot;HTTP_ACCEPT&quot;]" type="string" size="85" encoding="base64"><![CDATA[...]]></property><property name="HTTP_ACCEPT_ENCODING" fullname="$_SERVER[&quot;HTTP_ACCEPT_ENCODING&quot;]" type="string" size="17" encoding="base64"><![CDATA[...]]></property><property name="HTTP_ACCEPT_LANGUAGE" fullname="$_SERVER[&quot;HTTP_ACCEPT_LANGUAGE&quot;]" type="string" size="35" encoding="base64"><![CDATA[...]]></property><property name="PATH" fullname="$_SERVER[&quot;PATH&quot;]" type="string" size="29" encoding="base64"><![CDATA[...]]></property><property name="SERVER_SIGNATURE" fullname="$_SERVER[&quot;SERVER_SIGNATURE&quot;]" type="string" size="0" encoding="base64"><![CDATA[]]></property><property name="SERVER_SOFTWARE" fullname="$_SERVER[&quot;SERVER_SOFTWARE&quot;]" type="string" size="30" encoding="base64"><![CDATA[...]]></property><property name="SERVER_NAME" fullname="$_SERVER[&quot;SERVER_NAME&quot;]" type="string" size="9" encoding="base64"><![CDATA[...]]></property><property name="SERVER_ADDR" fullname="$_SERVER[&quot;SERVER_ADDR&quot;]" type="string" size="9" encoding="base64"><![CDATA[...]]></property><property name="SERVER_PORT" fullname="$_SERVER[&quot;SERVER_PORT&quot;]" type="string" size="2" encoding="base64"><![CDATA[...]]></property><property name="REMOTE_ADDR" fullname="$_SERVER[&quot;REMOTE_ADDR&quot;]" type="string" size="9" encoding="base64"><![CDATA[...]]></property><property name="DOCUMENT_ROOT" fullname="$_SERVER[&quot;DOCUMENT_ROOT&quot;]" type="string" size="35" encoding="base64"><![CDATA[...]]></property><property name="REQUEST_SCHEME" fullname="$_SERVER[&quot;REQUEST_SCHEME&quot;]" type="string" size="4" encoding="base64"><![CDATA[...]]></property><property name="CONTEXT_PREFIX" fullname="$_SERVER[&quot;CONTEXT_PREFIX&quot;]" type="string" size="0" encoding="base64"><![CDATA[]]></property><property name="CONTEXT_DOCUMENT_ROOT" fullname="$_SERVER[&quot;CONTEXT_DOCUMENT_ROOT&quot;]" type="string" size="35" encoding="base64"><![CDATA[...]]></property><property name="SERVER_ADMIN" fullname="$_SERVER[&quot;SERVER_ADMIN&quot;]" type="string" size="15" encoding="base64"><![CDATA[...]]></property><property name="SCRIPT_FILENAME" fullname="$_SERVER[&quot;SCRIPT_FILENAME&quot;]" type="string" size="44" encoding="base64"><![CDATA[...]]></property><property name="REMOTE_PORT" fullname="$_SERVER[&quot;REMOTE_PORT&quot;]" type="string" size="5" encoding="base64"><![CDATA[...]]></property><property name="GATEWAY_INTERFACE" fullname="$_SERVER[&quot;GATEWAY_INTERFACE&quot;]" type="string" size="7" encoding="base64"><![CDATA[...]]></property><property name="SERVER_PROTOCOL" fullname="$_SERVER[&quot;SERVER_PROTOCOL&quot;]" type="string" size="8" encoding="base64"><![CDATA[...]]></property><property name="REQUEST_METHOD" fullname="$_SERVER[&quot;REQUEST_METHOD&quot;]" type="string" size="3" encoding="base64"><![CDATA[...]]></property><property name="QUERY_STRING" fullname="$_SERVER[&quot;QUERY_STRING&quot;]" type="string" size="0" encoding="base64"><![CDATA[]]></property><property name="REQUEST_URI" fullname="$_SERVER[&quot;REQUEST_URI&quot;]" type="string" size="1" encoding="base64"><![CDATA[...]]></property><property name="SCRIPT_NAME" fullname="$_SERVER[&quot;SCRIPT_NAME&quot;]" type="string" size="10" encoding="base64"><![CDATA[...]]></property><property name="PHP_SELF" fullname="$_SERVER[&quot;PHP_SELF&quot;]" type="string" size="10" encoding="base64"><![CDATA[...]]></property><property name="REQUEST_TIME_FLOAT" fullname="$_SERVER[&quot;REQUEST_TIME_FLOAT&quot;]" type="float"><![CDATA[...]]></property><property name="REQUEST_TIME" fullname="$_SERVER[&quot;REQUEST_TIME&quot;]" type="int"><![CDATA[...]]></property></property></response>
[13856]
[13856] <- context_get -i 12 -d 0 -c 2
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="context_get" transaction_id="12" context="2"></response>
[13856]

/* Attempt to evaluate $a in the console */

[13856] <- eval -i 13 -- JGE=
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="eval" transaction_id="13"><property type="null"></property></response>
[13856]

/* Continue */

[13856] <- run -i 14
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="run" transaction_id="14" status="stopping" reason="ok"></response>
[13856]
[13856] <- stop -i 15
[13856] -> <response xmlns="urn:debugger_protocol_v1" xmlns:xdebug="https://xdebug.org/dbgp/xdebug" command="stop" transaction_id="15" status="stopped" reason="ok"></response>
[13856]
[13856] Log closed at 2019-03-04 16:48:03
[13856]
xdebug-log.txt (10,600 bytes)

derick

2019-03-04 17:27

administrator   ~0004932

Is opcache loaded and enabled? It's very possible that opcache simply optimised the variable away.

dv-ds

2019-03-04 17:36

reporter   ~0004933

Disabling opcache helps in this case, thanks, then I consider it a PHP bug for now.

For the other case I mentioned, it does not help however. I'll create a separate bug for that tomorrow. It happens at least when using each() - possibly due to the deprecation warning somehow.

dv-ds

2019-03-05 13:05

reporter   ~0004934

Created 1645.

As for this issue:

If you think this a PHP issue and that it might be solved in 7.3.2, please close this issue as I doubt I'll be able to test that theory anytime soon. I'm reluctant to upgrade to 7.3.2 just yet unless something breaks badly for me, as I've had problems with pretty much every PHP upgrade I've done using Homebrew. I can live with disabling the opcache for now.

derick

2019-03-05 13:27

administrator   ~0004935

Hi,

This is not a bug in PHP, but a feature. Opcache tries to make your code run faster, and to do so it optimises your PHP code. In this case, it optimises out the variable. You can see this when you compare the internal opcodes being generated without opcache loaded, against it being loaded:

Without Opcache

derick@singlemalt:~$ php -n -dextension=vld.so -dvld.active=1 /tmp/1644.php 
…
filename:       /tmp/1644.php
function name:  foobar
number of ops:  3
compiled vars:  !0 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   4     0  E >   ASSIGN                                                   !0, 42
   5     1        ECHO                                                     !0
   6     2      > RETURN                                                   null


With opcache
derick@singlemalt:~$ php -n -dzend_extension=opcache.so -dopcache.enable_cli=1 -dextension=vld.so -dvld.active=1 /tmp/1644.php 
…
filename:       /tmp/1644.php
function name:  foobar
number of ops:  2
compiled vars:  none
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   5     0  E >   ECHO                                                     42
   6     1      > RETURN                                                   null


The compiled variable !0 / $a is simply missing from the second example.

You can work around this by turning of opcache's optimisations in php.ini:

opcache.optimization_level = 0

Issue History

Date Modified Username Field Change
2019-03-04 17:13 dv-ds New Issue
2019-03-04 17:13 dv-ds File Added: xdebug-log.txt
2019-03-04 17:27 derick Assigned To => derick
2019-03-04 17:27 derick Status new => feedback
2019-03-04 17:27 derick Note Added: 0004932
2019-03-04 17:36 dv-ds Note Added: 0004933
2019-03-04 17:36 dv-ds Status feedback => assigned
2019-03-05 13:05 dv-ds Note Added: 0004934
2019-03-05 13:26 derick Status assigned => resolved
2019-03-05 13:26 derick Resolution open => no change required
2019-03-05 13:27 derick Note Added: 0004935