Rok Kralj
Rok Kralj

Reputation: 48715

@ error suppression operator and set_error_handler

I am following good programming practices and I am logging the PHP errors to file instead of displaying it to user. I use set_error_handler() for that.

Now the problem. For example, I have somewhere:

@file_exists('/some/file/that/is/outside/openbasedir.txt');

But despite the error suppression operator, the error message logs. I don't want that. I want suppressed errors not to pass to my error handler.

Upvotes: 26

Views: 3585

Answers (7)

Paul Pryor
Paul Pryor

Reputation: 21

Starting with PHP 8 - They changed error_reporting() to return the non-zero value "E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE" which is 4437 when handling error control operators. This is a bit unorthodox, but keep in mind that E_WARNING and other values are not set. I consider that a "magic" constant.

See Error Control Operators for description how error control operators are handled, and Set Error Handler first example how to ignore errors that are not enabled. Here is sample code to handle both error control operators and errors that are not enabled. It is important to check for error control operator first, then filter out the errors that are not enabled.

function errorHandler($errno, $errstr, $errfile, $errline)
{
  // catch error control operator and return
  if (error_reporting() ===
    E_ERROR |
    E_CORE_ERROR |
    E_COMPILE_ERROR |
    E_USER_ERROR |
    E_RECOVERABLE_ERROR |
    E_PARSE
  ) {
    return false;
  }

  // catch errors not being flagged
  if (!(error_reporting() & $errno)) {
    return false;
  }

  ...rest of error handler logic...
}

Upvotes: 0

MartinM
MartinM

Reputation: 11

PHP8 code 4437 for @

function myErrorHandler(int $errno, string  $errstr, ?string $errfile, ?int $errline) : void {
    if (error_reporting() !== 4437)
    {
      ......
    }
}

set_error_handler("myErrorHandler", E_ALL);

Upvotes: 1

Arnaud Le Blanc
Arnaud Le Blanc

Reputation: 99879

This answer applies at PHP 7:

The @ operator temporarily sets error_reporting to 0, so you can test the value of error_reporting in your error handler:

if (error_reporting() == 0)
    return;

Or even better, log only error types that are in error_reporting:

$error_reporting = error_reporting();
if ( !($error_reporting & $errno) )
    return;

Also take a look at the log_errors and error_log options, for automatically logging errors to a file or to syslog.

Upvotes: 36

Dima L.
Dima L.

Reputation: 3583

PHP8 behavior has changed and checking error_reporting() == 0 in the error handler no longer works. The way to check for errors suppressed with @ in PHP8 is as follows:

function errorHandler($err_severity, $err_msg, $err_file, $err_line)
{
    // Skip errors suppressed by @
    if (!(error_reporting() & $err_severity)) {
        return true;
    }

    // Error handling here
    return false;
}

Upvotes: 5

zxdx
zxdx

Reputation: 129

From manual:

Warning Prior to PHP 8.0.0, the error_reporting() called inside the custom error handler always returned 0 if the error was suppressed by the @ operator. As of PHP 8.0.0, it returns the value E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE.

This means that solutions from other answers will not work :(

The @-operator became completely unusable imho.

To disable errors you will have to do the following:

error_reporting(0); // disable

try {
    $res = 10/0;
} catch (Throwable){
    $res = false;
}

error_reporting(-1); // enable

Upvotes: 1

Simon Backx
Simon Backx

Reputation: 1372

Solution that also works for PHP 7

According to the PHP docs:

If you have set a custom error handler function with set_error_handler() then it will still get called, but this custom error handler can (and should) call error_reporting() which will return 0 when the call that triggered the error was preceded by an @.

Source: http://php.net/manual/en/language.operators.errorcontrol.php

So you can use the following code in your error handler:

function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    if (error_reporting() == 0) {
        /// @ sign temporary disabled error reporting
        return;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler("exception_error_handler");

Upvotes: 9

tereško
tereško

Reputation: 58444

You should actually avoid usage of @ operator. First of all, it is slow, and I would as far as to call it harmful.

What you should have instead is in php.ini file have two line:

error_repoting = E_ALL | E_STRICT
display_errors = Off

... or , if you do not have access to the php.ini file , then at the top of index.php (or any other bootstrap file) you should add :

error_reporting( E_ALL | E_STRICT );
ini_set('display_errors', 0);

Upvotes: 0

Related Questions