php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #61091 User-defined error handler run despite at sign (@) error control operator
Submitted: 2012-02-15 03:06 UTC Modified: 2012-04-16 21:01 UTC
From: chealer at gmail dot com Assigned:
Status: Not a bug Package: *General Issues
PHP Version: 5.3.10 OS:
Private report: No CVE-ID: None
 [2012-02-15 03:06 UTC] chealer at gmail dot com
Description:
------------
The at sign operator allows to "ignore" error messages, as explained in http://ca3.php.net/manual/en/language.operators.errorcontrol.php

When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored. 

However, user-defined error handlers registered with set_error_handler() are nevertheless run when @ is used, which often causes such messages to show, as in the below example, where a custom error handler is used to customize the display of error messages.

As http://ca3.php.net/manual/en/language.operators.errorcontrol.php#98895 and http://ca3.php.net/manual/en/language.operators.errorcontrol.php#85042 show, this problem is not new. This behavior appears to be by design, and might be wanted in some cases.

Therefore, please either:
Stop calling user-defined error handlers when suppressing errors. This needs serious consideration for backwards-compatibility.
Allow specifying whether user-defined error handlers should be called when suppressing errors.
Make the documentation reflect the current state of things.

Test script:
---------------
<?php

function myErrorHandler($errno, $errstr) {
    switch ($errno) {
    case E_USER_ERROR:
        echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
        echo "  Fatal error on line $errline in file $errfile";
        echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
        echo "Aborting...<br />\n";
        exit(1);
        break;

    case E_USER_WARNING:
        echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
        break;

    case E_USER_NOTICE:
        echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
        break;

    default:
        echo "Unknown error type: [$errno] $errstr<br />\n";
        break;
    }
}

// function to test the error handling
function scale_by_log($vect, $scale)
{
    if (!is_numeric($scale) || $scale <= 0) {
        trigger_error("log(x) for x <= 0 is undefined, you used: scale = $scale", E_USER_ERROR);
    }

    if (!is_array($vect)) {
        trigger_error("Incorrect input vector, array of values expected", E_USER_WARNING);
        return null;
    }

    $temp = array();
    foreach($vect as $pos => $value) {
        if (!is_numeric($value)) {
            trigger_error("Value at position $pos is not a number, using 0 (zero)", E_USER_NOTICE);
            $value = 0;
        }
        $temp[$pos] = log($scale) * $value;
    }

    return $temp;
}

$a = array(2, 3, "foo", 5.5, 43.3, 21.11);


/* Value at position $pos is not a number, using 0 (zero) */
scale_by_log($a, M_PI);
@scale_by_log($a, M_PI);

set_error_handler("myErrorHandler");
@scale_by_log($a, M_PI);

?>


Expected result:
----------------
Notice: Value at position 2 is not a number, using 0 (zero) in /var/www/atoperator.php on line 42

Call Stack:
    0.0005     339192   1. {main}() /var/www/atoperator.php:0
    0.0005     339836   2. scale_by_log(array (0 => 2, 1 => 3, 2 => 'foo', 3 => 5.5, 4 => 43.3, 5 => 21.11), 3.1415926535898) /var/www/atoperator.php:55
    0.0006     340648   3. trigger_error('Value at position 2 is not a number, using 0 (zero)', 1024) /var/www/atoperator.php:42

Actual result:
--------------
Notice: Value at position 2 is not a number, using 0 (zero) in /var/www/atoperator.php on line 42

Call Stack:
    0.0005     339192   1. {main}() /var/www/atoperator.php:0
    0.0005     339836   2. scale_by_log(array (0 => 2, 1 => 3, 2 => 'foo', 3 => 5.5, 4 => 43.3, 5 => 21.11), 3.1415926535898) /var/www/atoperator.php:55
    0.0006     340648   3. trigger_error('Value at position 2 is not a number, using 0 (zero)', 1024) /var/www/atoperator.php:42

<b>My NOTICE</b> [1024] Value at position 2 is not a number, using 0 (zero)<br />
 


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-02-15 03:45 UTC] rasmus@php.net
-Status: Open +Status: Not a bug
 [2012-02-15 03:45 UTC] rasmus@php.net
This is very much by design and definitely won't be changed since that would 
break all sorts of code. It is also explicitly documented at 
http://www.php.net/set_error_handler which explains that the user-defined error 
handler should check the error_reporting level in order to comply with the '@' if 
so desired.
 [2012-02-15 16:25 UTC] chealer at gmail dot com
Thanks rasmus, but I do not see this explanation. Could you quote it?
 [2012-02-15 16:53 UTC] rasmus@php.net
"error_reporting() settings will have no effect and your error handler will be 
called regardless - however you are still able to read the current value of 
error_reporting and act appropriately. Of particular note is that this value will 
be 0 if the statement that caused the error was prepended by the @ error-control 
operator."
 [2012-02-19 19:49 UTC] chealer at gmail dot com
Rasmus, the part you quoted is about error_reporting() settings, it merely mentions the error control operator.

My question was, could you quote where "http://www.php.net/set_error_handler [...] explains that the user-defined error 
handler should check the error_reporting level in order to comply with the '@' if so desired"?
 [2012-02-19 20:24 UTC] rasmus@php.net
It says, "however you are still able to read the current value of error_reporting 
and act appropriately" followed by "Of particular note is that this value will be 
0 if the statement that caused the error was prepended by the @ error-control 
operator."

To me this says quite clearly that error_reporting will be 0 if the @ was used 
and that your custom error handler can read this value and "act appropriately."
 [2012-02-19 21:59 UTC] chealer at gmail dot com
I guess it does, but this report is not about error_reporting, it is about the @ error control operator.

According to the documentation of @, any error message that might be generated by the expression will be "ignored". Either the PHP interpreter is changed so that this becomes the case, or, if the current behavior is desired, the documentation is adapted to reflect the actual semantics.

To be perfectly clear, I am not asking to change the de facto semantics. I am only asking that whatever semantics is used by the implementation matches the documented semantics.
 [2012-02-19 22:38 UTC] rasmus@php.net
But it is unless you choose to override the default behaviour. And the 
documentation you hit when you do this override tells you how to check for @.
 [2012-02-19 23:05 UTC] chealer at gmail dot com
I understand that this problem only happens when using a custom error handler. But, if we assume the bug is in the documentation, the documentation should not assume the error handler used is the standard one. The problem I'm reporting here is not that the documentation doesn't explain how custom error handlers should be written, it's just the quoted statement, which is wrong in certain cases.

Alternatively, if the documentation of the @ operator isn't amended because custom error handlers are considered a corner case, then the set_error_handler() documentation should warn developers tempted to use custom error handlers that they are non-standard, not recommended/supported, and try to explain the pitfalls. In short, tell developers they should only use a custom error handler if they know what they're doing.

However, this alternative should be avoided since set_error_handler() is already used in several applications whose developers didn't receive the warning.
 [2012-04-16 21:01 UTC] chealer at gmail dot com
This was fixed by rasmus in http://svn.php.net/viewvc/phpdoc/en/trunk/language/operators.xml?r1=322134&r2=323370

See also #61747.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed May 29 11:01:32 2024 UTC