Suppressing one expected PHP warning or notice keeps probe code, optional file reads, and fallback lookups quiet without muting diagnostics for the rest of the request. That is useful when a missing cache key, local file, or resource lookup is part of normal control flow instead of a real failure.
The @ error-control operator works on a single expression. PHP hides the visible diagnostic that expression would normally emit, but the expression still returns its usual success or failure value, error_get_last() still records the message, and any custom handler registered with set_error_handler() still runs.
The operator is intentionally narrow. Current PHP 8+ behavior no longer lets @ silence fatal termination, and many invalid-argument problems from built-in functions now raise TypeError or ValueError instead of ordinary warnings. The examples use one-command CLI overrides with -d so the behavior can be tested without changing persistent runtime settings such as php.ini.
$ php -d display_errors=1 -d log_errors=0 -r 'file_get_contents("/tmp/sg-missing-file");'
Warning: file_get_contents(/tmp/sg-missing-file): Failed to open stream: No such file or directory in Command line code on line 1
Matching the unsuppressed message first reduces the risk of hiding a different bug behind the same line of code.
$ php -d display_errors=1 -d log_errors=0 -r '$result = @file_get_contents("/tmp/sg-missing-file"); var_export($result); echo PHP_EOL;'
false
@ applies to expressions such as @file_get_contents($path) or @$cache[$key], not to control structures such as if or foreach.
$ php -d display_errors=1 -d log_errors=0 -r '$result = @file_get_contents("/tmp/sg-missing-file"); if ($result === false) { echo "using built-in application defaults".PHP_EOL; }'
using built-in application defaults
Use a direct guard such as is_file(), isset(), or array_key_exists() when one is available, because avoiding the warning is usually safer than suppressing it after the fact.
$ php -d display_errors=1 -d log_errors=0 -r 'error_clear_last(); $result = @file_get_contents("/tmp/sg-missing-file"); if ($result === false) { $last = error_get_last(); echo $last["message"].PHP_EOL; }'
file_get_contents(/tmp/sg-missing-file): Failed to open stream: No such file or directory
PHP updates the last-error array on each diagnostic, so clear and read it close to the suppressed expression instead of after unrelated work.
$ php -d display_errors=1 -d log_errors=0 -r 'error_reporting(E_ALL); set_error_handler(function($errno, $errstr){ echo "handler errno=$errno message=$errstr".PHP_EOL; echo "handler_mask=".error_reporting().PHP_EOL; return true; }); @trigger_error("optional local override not loaded", E_USER_WARNING);'
handler errno=512 message=optional local override not loaded
handler_mask=4437
The current PHP manual documents that error_reporting() inside the handler no longer returns 0 for suppressed diagnostics on PHP 8+. Use a mask check such as if (!(error_reporting() & $errno)) { return false; } when the handler needs to detect suppression.
$ php -d display_errors=1 -d log_errors=0 -r '@strlen([]);'
Fatal error: Uncaught TypeError: strlen(): Argument #1 ($string) must be of type string, array given in Command line code:1
Stack trace:
#0 {main}
thrown in Command line code on line 1
Use explicit validation, return-value checks, or try/catch when a failure must be handled cleanly. @ is appropriate only for a narrow, expected diagnostic.