View Issue Details

IDProjectCategoryView StatusLast Update
0001483XdebugUncategorizedpublic2019-12-08 07:32
Reporterclaude.bing Assigned Toderick  
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionno change required 
PlatformLinuxOSUbuntuOS Version16.04.3 LTS
Product Version2.5.5 
Summary0001483: Some function calls return NULL only when XDebug is enabled
Description

When I have XDebug enabled, a function call that is meant to return an array of objects will instead return NULL. If I disable XDebug, var_dump($variable); will return the correct information. The gist link in "Additional information" has two comments with output of var_dump() both with and without XDebug enabled.

Additional Information

https://gist.github.com/meinemitternacht/7838344bef9db1988bca9a8c8c4af165

It is not selectable in the list, but I am using PHP 7.1.10

TagsNo tags attached.
Attached Files
trace.manual.with-stmt-close (2,593,603 bytes)
Operating SystemUbuntu 16.04.3 LTS
PHP Version7.3.5-7.3.9

Activities

derick

2017-10-26 10:15

administrator   ~0004445

Please attach the code as a file here, so I can have a look when I'm offline too.

derick

2018-01-29 21:48

administrator   ~0004579

Can't reproduce this, and no feedback provided.

claude.bing

2019-08-03 19:17

reporter   ~0005101

Sorry I abandoned this issue, I got sidetracked with a lot of things.

I have reproduced this issue with the same project, but with a different OS version, PHP version, and Xdebug version. Similar to the original issue, the function returns an array of items, and adding a breakpoint in the function causes it to return null. If I do not add a breakpoint, it works fine.

Can you give me a list of things that would be most useful to you in order to debug the issue? Some sort of log from Xdebug, package versions, etc.

claude.bing

2019-08-03 20:23

reporter   ~0005103

I have (possibly) narrowed it down to closing a mysqli prepared statement before returning a value from the function. If I add a breakpoint after $stmt->close(), the function will return null. If I remove my container from the script, it produces a different problem entirely:

PHP Warning:  get_prospects(): Property access is not allowed yet in /home/vhosts/dla-dev/app/tools/test-xdebug.php on line 104
PHP Stack trace:
PHP   1. {main}() /home/vhosts/dla-dev/app/tools/test-xdebug.php:0
PHP   2. get_prospects($db = class mysqli { public $affected_rows = NULL; public $client_info = NULL; public $client_version = NULL; public $connect_errno = NULL; public $connect_error = NULL; public $errno = NULL; public $error = NULL; public $error_list = NULL; public $field_count = NULL; public $host_info = NULL; public $info = NULL; public $insert_id = NULL; public $server_info = NULL; public $server_version = NULL; public $stat = NULL; public $sqlstate = NULL; public $protocol_version = NULL; public $thread_id = NULL; public $warning_count = NULL }) /home/vhosts/dla-dev/app/tools/test-xdebug.php:113

Value of the $stmt variable in PhpStorm:

mysqli_stmt::__set_state(array(
   'affected_rows' => NULL,
   'insert_id' => NULL,
   'num_rows' => NULL,
   'param_count' => NULL,
   'field_count' => NULL,
   'errno' => NULL,
   'error' => NULL,
   'error_list' => NULL,
   'sqlstate' => NULL,
   'id' => NULL,
))
sample_script.php (2,764 bytes)   
<?php

use DI\Container;
use DownlineAutomator\Exceptions\Database\DatabaseConnectionFailedException;

/*
 * Using this manual connection method does not result in an error
$db = new mysqli(
    '127.0.0.1',
    'XXXXXXXX',
    'XXXXXXXX',
    'XXXXXXXX',
    3306,
    'unix:/var/run/mysqld/mysqld.sock'
);

if ($db->connect_errno) {
    throw new DatabaseConnectionFailedException(
        'Could not connect to the database'
    );
}

$db->set_charset('utf8mb4');
*/

/*
 * Using the container results in the function get_prospects() returning NULL instead of an array
 */
/** @var Container $container */
$container = require '../src/DownlineAutomator/Bootstrap.php';
$db = $container->get(mysqli::class);

xdebug_start_trace();
function get_prospects(mysqli $db) {
    $queryStr = <<<SQL
SELECT
  d.memberID,
  d.memberHasAutoship,
  d.dataReportingPeriod,
  d.memberPV
  FROM (
    SELECT
      downline_data.memberID,
      downline_data.memberHasAutoship,
      downline_data.dataReportingPeriod,
      downline_data.memberPV
    FROM downline_data
    LEFT JOIN downline_members ON downline_members.memberID = downline_data.memberID
    LEFT JOIN downline_members_inactive ON downline_data.memberID = downline_members_inactive.memberID
    WHERE downline_members.accountID = ?
      AND (downline_members.sponsorLeft BETWEEN ? AND ?)
      AND downline_members_inactive.memberID IS NULL
      AND (downline_data.dataReportingPeriod BETWEEN ? AND ?)
      AND downline_data.memberHasAutoship = 0
  ) d
SQL;

    $stmt = $db->prepare($queryStr);

    if ($stmt === false) {
        return null;
    }

    $data = [
        'accountId' => 123456789,
        'sponsorLeft' => 1,
        'sponsorRight' => 7262,
        'reportingPeriodStart' => 454,
        'reportingPeriodEnd' => 460,
    ];

    $stmt->bind_param(
        'iiiii',
        $data['accountId'],
        $data['sponsorLeft'],
        $data['sponsorRight'],
        $data['reportingPeriodStart'],
        $data['reportingPeriodEnd']
    );

    if (!$stmt->execute()) {
        $stmt->close();
        return null;
    }

    $stmt->bind_result(
        $memberId,
        $autoship,
        $reportingPeriod,
        $pv
    );

    $data = [];
    while ($stmt->fetch()) {
        $data[] = [
            'memberId' => $memberId,
            'autoship' => $autoship,
            'reportingPeriod' => $reportingPeriod,
            'pv' => $pv,
        ];
    }

    $stmt->close();

    $out = array_filter(
            $data,
            static function ($v) {
                return $v[ 'pv' ] >= 0;
            }
        );

    return $out;                                //BREAKPOINT HERE CAUSES NULL RETURN
}
$prospects = get_prospects($db);
var_dump($prospects);
xdebug_stop_trace();
sample_script.php (2,764 bytes)   

claude.bing

2019-08-03 20:26

reporter   ~0005104

1. trace.container.with-stmt-close:    DI Container + $stmt->close() before function return
2. trace.container.without-stmt-close: DI Container, no $stmt->close()
3. trace.manual.with-stmt-close:       new mysqli object + $stmt->close() before function return
4. trace.manual.without-stmt-close:    new mysqli object, no $stmt->close()

claude.bing

2019-08-03 20:40

reporter   ~0005105

The last thing I think is relevant is that the problem can be reproduced without the container if I register a custom error handler:

function exceptionErrorHandler($severity, $message, $file, $line)
{
    if (!(error_reporting() & $severity)) {
        // This error code is not included in error_reporting
        return;
    }
    throw new ErrorException($message, 0, $severity, $file, $line);
}

derick

2019-09-09 08:24

administrator   ~0005139

I believe it is this PHP bug that causes the issue: https://bugs.php.net/bug.php?id=67348&edit=1 — this got fixed in https://github.com/php/php-src/commit/579562176b71820ad49d43b2c841642fef12fe57 for PHP 7.4. As this is technically a BC break, it was not merge back to older PHP versions.

If you could try the latest 7.4.0RC1 version to test whether it solved this problem, that'd be great! If not, then I suggest we close the issue as I'm relatively sure, this is the cause of your issue.

claude.bing

2019-10-15 23:01

reporter   ~0005174

I will give this a shot and let you know how it goes!

derick

2019-11-25 07:43

administrator   ~0005186

Did you give this a go yet?

derick

2019-12-08 07:32

administrator   ~0005199

I'm closing this, as I believe this has been fixed in PHP 7.4. This was also never an issue in Xdebug either.

Issue History

Date Modified Username Field Change
2017-10-26 02:44 claude.bing New Issue
2017-10-26 10:15 derick Note Added: 0004445
2017-10-26 10:15 derick Assigned To => derick
2017-10-26 10:15 derick Status new => feedback
2018-01-29 21:48 derick Note Added: 0004579
2018-01-29 21:48 derick Status feedback => resolved
2018-01-29 21:48 derick Resolution open => unable to reproduce
2019-08-03 19:17 claude.bing Note Added: 0005101
2019-08-03 19:18 claude.bing Status resolved => new
2019-08-03 19:18 claude.bing Resolution unable to reproduce => reopened
2019-08-03 19:18 claude.bing PHP Version 7.1.5-7.1.9 => 7.3.5-7.3.9
2019-08-03 20:23 claude.bing File Added: trace.container.with-stmt-close
2019-08-03 20:23 claude.bing File Added: trace.container.without-stmt-close
2019-08-03 20:23 claude.bing File Added: trace.manual.with-stmt-close
2019-08-03 20:23 claude.bing File Added: trace.manual.without-stmt-close
2019-08-03 20:23 claude.bing File Added: sample_script.php
2019-08-03 20:23 claude.bing Note Added: 0005103
2019-08-03 20:26 claude.bing Note Added: 0005104
2019-08-03 20:40 claude.bing File Added: trace.manual.with-stmt-close.with-error-handler
2019-08-03 20:40 claude.bing Note Added: 0005105
2019-09-09 08:24 derick Status new => feedback
2019-09-09 08:24 derick Note Added: 0005139
2019-10-15 23:01 claude.bing Note Added: 0005174
2019-10-15 23:01 claude.bing Status feedback => assigned
2019-11-25 07:43 derick Status assigned => feedback
2019-11-25 07:43 derick Note Added: 0005186
2019-12-08 07:32 derick Status feedback => resolved
2019-12-08 07:32 derick Resolution reopened => no change required
2019-12-08 07:32 derick Note Added: 0005199
2020-03-12 16:35 derick Category Usage problems (Wrong Results) => Variable Display
2020-03-12 16:38 derick Category Variable Display => Uncategorized