The @ operator suppresses ALL error reporting for that statement:
- Hides bugs - Errors happen silently
- Breaks monitoring - Sentry, Rollbar, etc. never see the error
- Impossible to debug - No error message, no stack trace
- False sense of security - Code "works" but actually fails
// What @ actually does:
$old_level = error_reporting(0); // Disable error reporting
$result = file_get_contents('file.txt'); // Execute
error_reporting($old_level); // Restore error reportingError monitoring tools like Sentry only see errors that reach the error handler.
With @, error_reporting is temporarily 0, so:
- Error occurs
- PHP checks
error_reporting→ it's 0 - Error is suppressed, never reaches error handler
- Sentry never sees it!
// WRONG: Hides file not found error
$content = @file_get_contents('config.json');
// WRONG: Hides division by zero
$average = @($total / $count);
// WRONG: Hides undefined index
$name = @$_POST['name'];Problems:
- No error message when it fails
- Sentry won't capture it
- Returns
nullorfalsewith no explanation - Debugging is impossible
// GOOD: Check before reading
if (!file_exists($file)) {
error_log("File not found: {$file}");
return null;
}
$content = file_get_contents($file);
if (false === $content) {
error_log("Failed to read file: {$file}");
return null;
}// GOOD: Validate before dividing
if ($count <= 0) {
error_log('Cannot divide by zero');
return 0.0;
}
return $total / $count;// GOOD: Use null coalescing
$name = $_POST['name'] ?? '';
// Or check isset
if (!isset($_POST['name'])) {
wp_die('Name is required');
}// GOOD: Check each step
$response = wp_remote_get($url);
if (is_wp_error($response)) {
error_log('API error: ' . $response->get_error_message());
return null;
}
$code = wp_remote_retrieve_response_code($response);
if (200 !== $code) {
error_log("API returned {$code}");
return null;
}// "I'll just suppress this for now..."
@include $file;
// Famous last words. This becomes permanent.// "I know this throws a notice, it's fine"
$value = @$array['key'];
// Not fine. Fix the root cause instead.// "The library is buggy, I need @"
@$buggy_library->method();
// Report the bug, fork the library, or find alternative.if (file_exists($file)) {
$content = file_get_contents($file);
}if ($count > 0) {
$average = $total / $count;
}try {
$result = dangerous_operation();
} catch (Exception $e) {
error_log($e->getMessage());
}$value = $data['key'] ?? 'default';class Result {
public static function success($value) { }
public static function failure($error) { }
}// BAD: Sentry never sees this
@file_get_contents('file.txt');
// GOOD: Sentry captures the error
if (!file_exists('file.txt')) {
error_log('File not found');
// Sentry sees this error log
}With proper error handling:
- Errors are logged
- Sentry captures them
- You get notifications
- Stack traces are available
- Debugging is possible
✅ Never use @ operator
✅ Check conditions before operations
✅ Use null coalescing for array access
✅ Log errors explicitly
✅ Let monitoring tools see errors
✅ Fix root causes, don't suppress
❌ Don't suppress errors with @
❌ Don't use @ as a "quick fix"
❌ Don't suppress "known" issues
❌ Don't break error monitoring
❌ Don't make debugging impossible
@ is like putting duct tape over your check engine light.
The problem is still there, you just can't see it anymore.
// This makes you blind to errors:
@file_get_contents('config.json');
// This makes errors visible and fixable:
if (!file_exists('config.json')) {
error_log('Config file missing');
return null;
}Remove all @ from your code. Handle errors properly.
Your future self (and your monitoring tools) will thank you!