PHP Australia Conference 2015

エラー制御演算子

PHP はエラー制御演算子(@)をサポートしています。PHP の式の前に付けた場合、 その式により生成されたエラーメッセージは無視されます。

set_error_handler() で自作のエラーハンドラを設定した場合は エラー制御演算子があってもそのエラーハンドラがコールされます。 しかし、自作のエラーハンドラの中で error_reporting() をコールすれば、@ つきの式で生成されたエラーの場合は返り値が 0 になるのでこの値で区別することができます。 自作のエラーハンドラの中ではこの方法による区別を行うべきです。

track_errors 機能が 有効な場合、式により生成されたエラーメッセージはグローバル変数 $php_errormsg に保存されます。この変数はエラーが発生するたびに上書きされます。 そのため、この変数を使用したい場合には速やかに確認する必要があります。

<?php
/* 意図的なエラー */
$my_file = @file ('non_existent_file') or
    die (
"Failed opening file: error was '$php_errormsg'");

// この演算子は関数だけでなく、全ての式で動作します。
$value = @$cache[$key]; 
// インデックス $key が存在しない場合でも、警告を発生しません。

?>

注意: @演算子は、 でのみ動作します。基本的なルールは次のようになります。 値を得ることができるものの場合、@ 演算子を前に付けることが可能です。 例えば、変数、関数、include コール、定数等の 前にこの演算子をつけることが可能です。関数またはクラスの定義や ifforeach 等のような 条件構造の前にこの演算子を付けることはできません。

error_reporting() と、 エラー処理とログ出力関数 も参照してください。

警告

現在、エラー制御演算子プレフィックス"@"は、スクリプトの実行を 終了するような致命的なエラーの出力さえ抑圧します。このため、ある関数の エラー出力を抑制するために "@" を使用した場合、その関数が 利用できなかったり、ミスタイプがあった場合でも、原因を示すことなく その場所でスクリプトは終了してしまいます。

add a note add a note

User Contributed Notes 16 notes

up
84
Anonymous
1 year ago
This operator is affectionately known by veteran phpers as the stfu operator.
up
40
taras dot dot dot di at gmail dot com
6 years ago
I was confused as to what the @ symbol actually does, and after a few experiments have concluded the following:

* the error handler that is set gets called regardless of what level the error reporting is set on, or whether the statement is preceeded with @

* it is up to the error handler to impart some meaning on the different error levels. You could make your custom error handler echo all errors, even if error reporting is set to NONE.

* so what does the @ operator do? It temporarily sets the error reporting level to 0 for that line. If that line triggers an error, the error handler will still be called, but it will be called with an error level of 0

Hope this helps someone
up
16
anthon at piwik dot org
3 years ago
If you're wondering what the performance impact of using the @ operator is, consider this example.  Here, the second script (using the @ operator) takes 1.75x as long to execute...almost double the time of the first script.

So while yes, there is some overhead, per iteration, we see that the @ operator added only .005 ms per call.  Not reason enough, imho, to avoid using the @ operator.

<?php
function x() { }
for (
$i = 0; $i < 1000000; $i++) { x(); }
?>

real    0m7.617s
user    0m6.788s
sys    0m0.792s

vs

<?php
function x() { }
for (
$i = 0; $i < 1000000; $i++) { @x(); }
?>

real    0m13.333s
user    0m12.437s
sys    0m0.836s
up
16
auser at anexample dot com
4 years ago
Be aware that using @ is dog-slow, as PHP incurs overhead to suppressing errors in this way. It's a trade-off between speed and convenience.
up
18
M. T.
4 years ago
Be aware of using error control operator in statements before include() like this:

<?PHP

(@include("file.php"))
OR die(
"Could not find file.php!");

?>

This cause, that error reporting level is set to zero also for the included file. So if there are some errors in the included file, they will be not displayed.
up
11
gerrywastaken
5 years ago
Error suppression should be avoided if possible as it doesn't just suppress the error that you are trying to stop, but will also suppress errors that you didn't predict would ever occur. This will make debugging a nightmare.

It is far better to test for the condition that you know will cause an error before preceding to run the code. This way only the error that you know about will be suppressed and not all future errors associated with that piece of code.

There may be a good reason for using outright error suppression in favor of the method I have suggested, however in the many years I've spent programming web apps I've yet to come across a situation where it was a good solution. The examples given on this manual page are certainly not situations where the error control operator should be used.
up
7
programming at kennebel dot com
7 years ago
To suppress errors for a new class/object:

<?php
// Tested: PHP 5.1.2 ~ 2006-10-13

// Typical Example
$var = @some_function();

// Class/Object Example
$var = @new some_class();

// Does NOT Work!
//$var = new @some_class(); // syntax error
?>

I found this most useful when connecting to a
database, where i wanted to control the errors
and warnings displayed to the client, while still
using the class style of access.
up
6
bohwaz
3 years ago
If you use the ErrorException exception to have a unified error management, I'll advise you to test against error_reporting in the error handler, not in the exception handler as you might encounter some headaches like blank pages as error_reporting might not be transmitted to exception handler.

So instead of :

<?php

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

set_error_handler("exception_error_handler");

function
catchException($e)
{
    if (
error_reporting() === 0)
    {
        return;
    }

   
// Do some stuff
}

set_exception_handler('catchException');

?>

It would be better to do :

<?php

function exception_error_handler($errno, $errstr, $errfile, $errline )
{
    if (
error_reporting() === 0)
    {
        return;
    }

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

set_error_handler("exception_error_handler");

function
catchException($e)
{
   
// Do some stuff
}

set_exception_handler('catchException');

?>
up
1
darren at powerssa dot com
4 years ago
After some time investigating as to why I was still getting errors that were supposed to be suppressed with @ I found the following.

1. If you have set your own default error handler then the error still gets sent to the error handler regardless of the @ sign.

2. As mentioned below the @ suppression only changes the error level for that call. This is not to say that in your error handler you can check the given $errno for a value of 0 as the $errno will still refer to the TYPE(not the error level) of error e.g. E_WARNING or E_ERROR etc

3. The @ only changes the rumtime error reporting level just for that one call to 0. This means inside your custom error handler you can check the current runtime error_reporting level using error_reporting() (note that one must NOT pass any parameter to this function if you want to get the current value) and if its zero then you know that it has been suppressed.
<?php
// Custom error handler
function myErrorHandler($errno, $errstr, $errfile, $errline)
{
    if (
0 == error_reporting () ) {
       
// Error reporting is currently turned off or suppressed with @
       
return;
    }
   
// Do your normal custom error reporting here
}
?>

For more info on setting a custom error handler see: http://php.net/manual/en/function.set-error-handler.php
For more info on error_reporting see: http://www.php.net/manual/en/function.error-reporting.php
up
0
frogger at netsurf dot de
9 years ago
Better use the function trigger_error() (http://de.php.net/manual/en/function.trigger-error.php)
to display defined notices, warnings and errors than check the error level your self. this lets you write messages to logfiles if defined in the php.ini, output
messages in dependency to the error_reporting() level and suppress output using the @-sign.
up
-1
beatngu
6 years ago
NB The @ operator doesn't work when throwing errors as exceptions using the ErrorException class
up
-1
Anonymous
7 years ago
error_reporting()==0 for detecting the @ error suppression assumes that you did not set the error level to 0 in the first place.

However, typically if you want to set your own error handler, you would set the error_reporting to 0. Therefore, an alternative to detect the @ error suppression is required.
up
-2
nospam at blog dot fileville dot net
7 years ago
If you want to log all the error messages for a php script from a session you can use something like this:
<?php
session_start
();
  function
error($error, $return=FALSE) {
      global
$php_errormsg;
      if(isset(
$_SESSION['php_errors'])) {
       
$_SESSION['php_errors'] = array();    
    }
 
$_SESSION['php_errors'][] = $error; // Maybe use $php_errormsg
 
if($return == TRUE) {
   
$message = "";
       foreach(
$_SESSION['php_errors'] as $php_error) {
         
$messages .= $php_error."\n";
     } 
    return
$messages; // Or you can use use $_SESSION['php_errors']
 
}
}
?>
Hope this helps someone...
up
-3
me at hesterc dot fsnet dot co dot uk
9 years ago
If you wish to display some text when an error occurs, echo doesn't work. Use print instead. This is explained on the following link 'What is the difference between echo and print?':

http://www.faqts.com/knowledge_base/view.phtml/aid/1/fid/40

It says "print can be used as part of a more complex expression where echo cannot".

Also, you can add multiple code to the result when an error occurs by separating each line with "and". Here is an example:

<?php
$my_file
= @file ('non_existent_file') or print 'File not found.' and $string = ' Honest!' and print $string and $fp = fopen ('error_log.txt', 'wb+') and fwrite($fp, $string) and fclose($fp);
?>

A shame you can't use curly brackets above to enclose multiple lines of code, like you can with an if statement or a loop. It could make for a single long line of code. You could always call a function instead.
up
-4
Anonymous
7 months ago
I was wondering if anyone (else) might find a directive to disable/enable to error operator would be a useful addition. That is, instead of something like (which I have seen for a few places in some code):

<?php

if (defined(PRODUCTION)) {
    @function();
}
else {
    function();
}

?>

There could be something like this:

<?php

if (defined(PRODUCTION)) {
   
ini_set('error.silent',TRUE);
}
else {
   
ini_set('error.silent',FALSE);
}

?>
up
-11
dsbeam at gmail dot com
5 years ago
Though error suppression can be dangerous at times, it can be useful as well.  I've found the following statements roughly equivalent:

     if( isset( $var ) && $var === $something )
     if( @$var === $something )

EXCEPT when you're comparing against a boolean value (when $something is false).  In that case, if it's not set the conditional will still be triggered.

I've found this useful when I want to check a value that might not exist:

     if( @$_SERVER[ 'HTTP_REFERER' ] !== '/www/some/path/file' )

or when we want to see if a checkbox / radio button have been submitted with a post action

     if( @$_POST[ 'checkbox' ] === 'yes' )

Just letting you guys know my findings, :)
To Top