Rudie
Rudie

Reputation: 53881

Detect (in custom error handler) if a PHP error was actually suppressed by @

Context:

I have three environments for an app: dev (local), test/staging (prod server), production. The app knows which is which. Error reporting on both staging and production is 0, so errors are never shown. On dev I want to see errors immediately and I want to see them where they happen, so not in some log, but in the code's result.

However, I don't want to see the errors I have explicitly suppressed with @. I've been using fsockopen and that throws a warning when it can't connect. I accept the no-connection, but don't want to see the error. Not even on dev.

Apparantly all errors go though the custom error handler, even if they were suppressed in the code.

My error handler has only 4 arguments: errno, error, file, line. From those I can't see whether the error was originally suppressed or not. If I can see that there, I can choose whether to print the error (right now I always do, if env=dev).

Any ideas? Or maybe on how to completely ignore suppressed errors (so that they don't even reach the custom error handler)?

Upvotes: 12

Views: 2415

Answers (4)

Add this too your handler

   // error was suppressed with the @-operator
    if (0 === error_reporting()) { return false;}

Upvotes: 0

Richard
Richard

Reputation: 2110

For PHP 8.0

So in PHP 8.0, you can no longer tell if the error/warning/notice, etc, was suppressed (using @) simply by checking if error_reporting() == 0.

Instead, it is now a fairly long piece of bitwise operators with constants, described in a warning box here: https://www.php.net/manual/en/language.operators.errorcontrol.php

Fix for both PHP 7.x and 8.x

In your custom error handler, if you want to tell if your error was suppressed with the @ sign, use something like this:

$PHP_8_SUPPRESSED = E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE;
$er = error_reporting();  
    
if ($er === 0 || $er === $PHP_8_SUPPRESSED) { 
  // do code because it was suppressed.  Ex: return FALSE, etc.
} 

At the time of this writing, $PHP_8_SUPPRESSED will equal integer value 4437, but it's probably best not to hard-code that, since future versions of PHP might change these constant values.

Quick side note: I really wish they had just created a new constant called "E_SUPPRESSED_ERROR" or something like that we could check. But sadly they did not!

Upvotes: 8

user187291
user187291

Reputation: 53950

A proper way to handle errors in php

  • do not use error_reporting
  • install an errors-to-exceptions handler ( http://www.php.net/manual/en/class.errorexception.php , example 1) and convert all php "errors" to exceptions
  • in your main code, use try-catch where appropriate
  • install an exception handler to catch exceptions not caught in the main code. This handler is the only place where you output and/or log errors.
  • do not use @. In a rare case you want to ignore an error, use an empty catch block
  • use some stupid trick to catch "fatal" errors. Better yet, contact php group and try to convince them to make "fatal" errors handleable in scripts.

Upvotes: 1

Adam Hopkinson
Adam Hopkinson

Reputation: 28793

There's a hint to this in the set_error_handler manual page.

[the error_reporting()] value will be 0 if the statement that caused the error was prepended by the @ error-control operator

When you use the error control operator @, what is happening is this:

  1. error reporting is set to 0 (no errors) - error_reporting(0)
  2. the expression is evaluated
  3. error reporting is set back to the previous value (ie turned back on)

The slightly confusing quote above refers to the fact that error_reporting returns the current setting. If you have suppressed the error with the control operator, calling error_reporting() will return 0.

Therefore, if you know you have set it to non-zero (ie you are reporting some errors) and it returns zero, you know the error was suppressed.

If you detect a suppressed error and want to know what it was, you can find it in the variable $php_errormsg (if track_errors is set to true in php.ini).

Note that the error control operator causes a lot of overhead, as it changes the error reporting level twice each time it is used. It will slow down your script.

Upvotes: 22

Related Questions