Skip to content

error_get_last() is not set when errors are logged #5587

Closed
@mvorisek

Description

@mvorisek

related with #5428

Q A
PHPUnit version 10.4.2
PHP version 8.2.12
Installation Method Composer

Summary

Current behavior

error_get_last() is not set when errors are logged (PHPUnit error handler is active). The errors are logged by default which is a good. But the current impl. of the error handler causes code that relies on error_get_last() set after a core php function has returned a failure like:

$dirHandle = opendir($dirPath);
if ($dirHandle === false) {
    $errorMessage = preg_replace('~^.+?:\s*~s', '', error_get_last()['message']);
}

to fail as error_get_last() is empty.

This is because the current impl. of the error handler returns true [1] when an error is handled. The php docs say [2]:

It is important to remember that the standard PHP error handler is completely bypassed for the error types specified by error_levels unless the callback function returns false.

[1] https://github.com/sebastianbergmann/phpunit/blob/10.4.2/src/Runner/ErrorHandler.php#L144
[2] https://www.php.net/manual/en/function.set-error-handler.php

The issue is present since PHPUnit 10, in PHPUnit 9 and lower error_get_last() was set correctly.

How to reproduce

$dirHandle = opendir('/--non-existing-path--');
self::assertNotNull(error_get_last());

Expected behavior

The PHPUnit handler should:

  1. log an error
  2. suppress its output
  3. not affect the error_get_last() result, the result must be the same /w and /wo PHPUnit error handler active

I tried to workaround about this issue https://3v4l.org/kS1vM/rfc#vgit.master but if the output is suppressed by lowering the reporting level when handling the error, it seems there is no way to restore the level back immediatelly after the error handling is finished.

I belive the solution is to modify the PHPUnit error handler:

  1. to return false when handling the error - it will let php to handle the error natively
  2. to backup the current error_reporting() level and set it to error_reporting(error_reporting() & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)) when the handler activates (the listed error levels cannot be handled by an user handler [2])
  3. to restore the backed error level when the error handler deactivates (or better increase the current error level if lower than the backed one)
  4. e676667 original fix and c2c8dbb can be reverted then, no WithoutErrorHandler attribute needed

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/bugSomething is brokenversion/10Something affects PHPUnit 10

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions