Edit report at https://bugs.php.net/bug.php?id=61747&edit=1
ID: 61747
User updated by: chealer at gmail dot com
Reported by: chealer at gmail dot com
Summary: User-defined error handler run despite at sign (@)
error control operator
Status: Not a bug
Type: Bug
Package: *General Issues
PHP Version: 5.4.0
Block user comment: N
Private report: N
New Comment:
I meant it would be inefficient to ask PHP programmers to include
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting
return;
}
in all custom error handlers they write, if the problem could be addressed once
and for all by the PHP interpreter.
If that is your stance though, this requirement should be documented in
http://ca3.php.net/manual/en/function.set-error-handler.php
And if you really think that custom error handlers should ignore suppressed
errors, then not calling custom error handlers would be more of a bugfix (for
those handlers that fail to do it) than a BC break. Certainly, that wouldn't be
a "major BC break", although it may be disruptive enough to warrant waiting for
a major release to do such a behavior change.
I'm not saying there's something *wrong* (in the sense of buggy) with the
current implementation, as long as how it works is documented (which wasn't the
case until recently), and the requirement to check for suppressed errors is
documented in set_error_handler()'s documentation (which is still not the case).
Previous Comments:
------------------------------------------------------------------------
[2012-04-16 21:31:03] [email protected]
There is nothing inefficient about calling error_reporting(). It is a trivially
small and fast internal function. And like I said, changing anything here would
be a major BC break. There is nothing wrong with the current implementation.
------------------------------------------------------------------------
[2012-04-16 21:23:27] chealer at gmail dot com
This is a duplicate of #52338.
Note that I partly disagree with the fix. Custom error handlers *can* check
error_reporting(), as illustrated in the example from
http://ca3.php.net/manual/en/function.set-error-handler.php
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno)) {
// This error code is not included in error_reporting
return;
}
[...]
}
However, it would be rather inefficient if custom error handlers *should* (had
to) do that, in general. If that was the case, PHP should simply not call
user-defined error handlers when @ was used.
I think user-defined error handlers *should* do something like that, but only
in some cases.
------------------------------------------------------------------------
[2012-04-16 20:59:18] chealer at gmail dot com
I'm sorry. This was fixed in
http://svn.php.net/viewvc/phpdoc/en/trunk/language/operators.xml?r1=322134&r2=323370
We now have:
When prepended to an expression in PHP, any error messages that might be
generated by that expression will be ignored.
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 @.
Note that this second sentence contradicts the first in some [edge] cases. At
least, the second sentence should immediately follow the first, rather than
having its own paragraph.
------------------------------------------------------------------------
[2012-04-16 20:39:54] [email protected]
The documentation is quite clear I think. In the first link you provided it
says:
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 @.
I see no reason to change anything here. The current approach gives you all the
control you need. If you have a custom error handler you can decide whether you
want to ignore silenced calls or not. Any change to this would also be a major
BC break.
------------------------------------------------------------------------
[2012-04-16 17:57:52] 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, as reported in #61091, 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.
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.
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
/>
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=61747&edit=1