Skip to content

PHP Error Handling

Effective error handling is crucial for building robust and secure PHP applications. It involves detecting errors, reporting them appropriately (logging for developers, user-friendly messages for users), and potentially recovering from them.

PHP distinguishes between several types of issues:

  • Notices: Non-critical issues found during script execution (e.g., using an undefined variable). Execution usually continues.
  • Warnings: More serious non-fatal errors (e.g., including a non-existent file). Execution usually continues.
  • Fatal Errors: Critical errors that halt script execution (e.g., calling an undefined function, parse errors). In PHP 7+, many of these now throw Error exceptions.
  • Exceptions: Object-oriented way to handle runtime errors or exceptional conditions (Exception and Error classes implementing Throwable). Covered in the Exceptions chapter.

Modern PHP relies heavily on the Exception model (try...catch...finally) for handling runtime problems, including many errors that were previously fatal.

Basic Error Handling: The die() or exit() Construct

Section titled “Basic Error Handling: The die() or exit() Construct”

A very simple, but often crude, way to handle a fatal condition is to stop script execution using die() or exit() (they are aliases).

Example: Checking file existence before opening:

<?php
$filename = "nonexistent_file.txt";
if (!file_exists($filename)) {
// Stop script execution and output a message
die("Error: File '{$filename}' not found. Cannot proceed.");
}
// This code will only run if the file exists
echo "File exists, proceeding...";
$fileHandle = fopen($filename, "r");
// ... process file ...
?>

While die() prevents further execution after a critical error, it provides a poor user experience and bypasses any cleanup logic (like closing database connections). It’s generally discouraged in favor of exceptions or more graceful error handling in production applications.

PHP’s error reporting behavior is controlled by settings in the php.ini configuration file or dynamically within scripts using functions like error_reporting() and ini_set().

Key Directives (php.ini):

  • error_reporting (e.g., E_ALL): Sets the level of errors that PHP should report. E_ALL is recommended during development to catch all issues (notices, warnings, etc.).
  • display_errors (e.g., On or Off): Determines whether errors should be displayed directly in the browser output. Should be On during development but strictly Off in production to avoid exposing sensitive information.
  • log_errors (e.g., On or Off): Determines whether errors should be written to a log file. Should be On in production.
  • error_log (e.g., /var/log/php_errors.log or syslog): Specifies the file or system logger where errors should be logged when log_errors is On.

Development vs. Production Settings:

  • Development: error_reporting = E_ALL, display_errors = On, log_errors = On (optional, but good).
  • Production: error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT (or similar, report most things except notices/deprecations if desired), display_errors = Off, log_errors = On, error_log = /path/to/secure/log/file.

You can override php.ini settings temporarily in a script:

<?php
// Recommended for development: Show all errors
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
// Example of triggering a notice
echo $undefinedVariable;
// Code that might cause a warning
include 'non_existent_file.php';
?>

For non-exception errors (primarily notices and warnings), you can define a custom function to handle them using set_error_handler(). This allows you to intercept these errors and decide how to log or display them.

This is less commonly needed now that many fatal errors throw Error exceptions, but it can still be useful for logging notices/warnings during development or converting specific warnings into exceptions.

The handler function receives parameters like error level, message, file, line number, and context.

Syntax: set_error_handler(callable $callback, int $error_levels = E_ALL | E_STRICT)

Example: Logging warnings and notices:

<?php
declare(strict_types=1);
// Custom error handler function
function customErrorHandler(int $errno, string $errstr, string $errfile, int $errline): bool
{
// Log the error (adjust path and format as needed)
$logMessage = "[" . date("Y-m-d H:i:s") . "] Error [$errno]: $errstr in $errfile on line $errline\n";
error_log($logMessage, 3, "/path/to/your/app_errors.log");
// To prevent PHP's internal handler from running, return true.
// If you return false or nothing, PHP's standard error handling will proceed.
// Don't display errors directly in production!
if (ini_get('display_errors')) { // Only display if configured
echo "**Error Caught:** [$errno] $errstr in $errfile:$errline<br>";
}
// Let PHP continue if it's just a notice/warning, but halt for user errors maybe?
// This logic depends on your needs.
/*
switch ($errno) {
case E_USER_ERROR:
echo "Fatal error caught. Halting.";
exit(1);
break;
case E_USER_WARNING:
case E_USER_NOTICE:
// Logged above, continue execution
break;
default:
// Standard PHP notice/warning, logged above, continue execution
break;
}
*/
return true; // Suppress PHP's default handler for handled types
}
// Set the custom handler to catch all errors (including notices, warnings)
set_error_handler('customErrorHandler', E_ALL);
// Trigger a notice
echo $someUndefinedVar;
// Trigger a warning
include 'non_existent_script.php';
echo "Script execution might continue depending on handler logic...";
?>

Note: The custom error handler set by set_error_handler() cannot handle fatal errors like parse errors or most errors that now throw Error exceptions in PHP 7+. Use register_shutdown_function() for some fatal error detection or try...catch (Throwable $t) for exceptions/errors.

You can generate user-level errors (notices, warnings, or fatal errors) from within your code using the trigger_error() function. This is useful for indicating problems in your application logic or library usage.

Syntax: trigger_error(string $message, int $error_type = E_USER_NOTICE)

Error Types:

  • E_USER_NOTICE (Default): Like a standard PHP notice.
  • E_USER_WARNING: Like a standard PHP warning.
  • E_USER_ERROR: Like a fatal PHP error (halts execution unless handled by a custom error handler that exits).
  • E_USER_DEPRECATED: Indicate deprecated functionality.

Example:

<?php
function calculateDivision(float $numerator, float $denominator): float {
if ($denominator == 0) {
// Trigger a user warning for invalid input
trigger_error("Division by zero attempted", E_USER_WARNING);
return NAN; // Not a Number
}
if ($numerator < 0) {
// Example: Trigger a notice if numerator is negative
trigger_error("Numerator is negative, proceeding anyway.", E_USER_NOTICE);
}
return $numerator / $denominator;
}
// Set a simple error handler to see the triggered errors
set_error_handler(function($errno, $errstr){
echo "Triggered Error: $errstr\n";
}, E_USER_NOTICE | E_USER_WARNING);
$result1 = calculateDivision(10, 0);
echo "Result 1: $result1\n";
$result2 = calculateDivision(-5, 2);
echo "Result 2: $result2\n";
?>

Output:

Triggered Error: Division by zero attempted
Result 1: NAN
Triggered Error: Numerator is negative, proceeding anyway.
Result 2: -2.5

The error_log() function allows you to explicitly send messages to PHP’s configured error log mechanism (file, syslog) or even via email (though email logging is generally discouraged for high volume).

This is useful for logging specific application events or detailed debug information separate from standard PHP errors.

Syntax: error_log(string $message, int $message_type = 0, ?string $destination = null, ?string $additional_headers = null): bool

Common message_type values:

  • 0 (Default): Send message to PHP’s system logger (uses error_log directive in php.ini).
  • 1: Send message via email to the address specified in the destination parameter.
  • 3: Append message to the file specified in destination.

Example: Logging a custom message to the standard PHP error log:

<?php
$userId = 123;
$action = "update_profile";
// ... some logic ...
if (/* some condition indicating success */ true) {
$logMsg = "User ID {$userId} successfully performed action '{$action}'.";
error_log($logMsg); // Sends to the configured PHP error log (type 0)
echo "Action logged.";
} else {
$logMsg = "User ID {$userId} failed action '{$action}'.";
error_log($logMsg); // Log failure too
echo "Action failure logged.";
}
?>

Example: Logging to a specific file (ensure permissions are correct):

<?php
$customLogFile = '/var/log/my_app_debug.log'; // Make sure this file is writable by the web server
$debugInfo = "Processing started for request ID: " . uniqid();
error_log(date('[Y-m-d H:i:s] ') . $debugInfo . "\n", 3, $customLogFile);
echo "Debug info written to custom log.";
?>

Caution: Avoid logging sensitive data like passwords or personal information.