Error Handling

Su Subhalakshmi Chandran Updated 17 Oct 2026
6 min read ·Lesson 94 of 109
In this post

Errors in PHP In simple terms: When something goes wrong in a PHP script, PHP reports it — sometimes as a mild warning while the script continues, sometimes as a fatal error that stops everything. Err

Errors in PHP

In simple terms: When something goes wrong in a PHP script, PHP reports it — sometimes as a mild warning while the script continues, sometimes as a fatal error that stops everything. Error handling means deciding how these problems are reported, recorded, and shown (or hidden) to users, and writing code that deals with failures gracefully.

Technically: PHP has two error mechanisms:

MechanismExamplesHow It Behaves
Traditional errors (diagnostics)Warnings, notices, deprecationsReported according to error_reporting; the script usually continues
Throwables (exceptions and Error)TypeError, ValueError, DivisionByZeroError, your own exceptionsCan be caught with try/catch; uncaught ones stop the script

Since PHP 7 and especially PHP 8, many former fatal errors and warnings were converted into Error exceptions, which can be caught. Exceptions are covered in PHP Exceptions; this lesson covers the traditional errors and the overall strategy.


Error Levels

ConstantSeverityExampleScript Continues?
E_ERRORFatal runtime errorMemory limit exhaustedNo
E_PARSESyntax errorMissing semicolonNo (the file cannot run)
E_WARNINGWarningFile not found in file_get_contents()Yes
E_NOTICENoticeMinor issues (few remain in PHP 8)Yes
E_DEPRECATEDDeprecationUsing a feature that will be removedYes
E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, E_USER_DEPRECATEDTriggered by your code with trigger_error()CustomDepends
E_ALLAll of the above——

Version notes: E_STRICT is deprecated as of PHP 8.4 (its messages were merged into other levels long ago). Passing E_USER_ERROR to trigger_error() is deprecated in PHP 8.4 — throw an exception instead.

Example: Warnings and Deprecations Do Not Stop the Script

<?php
$prices = [10, 20];

$price = $prices[5];
$total = $undefined;
$length = strlen(null);

echo "Still running\n";

Output

PHP Warning:  Undefined array key 5 in /path/script.php on line 4
PHP Warning:  Undefined variable $undefined in /path/script.php on line 5
PHP Deprecated:  strlen(): Passing null to parameter #1 ($string) of type string is deprecated in /path/script.php on line 6
Still running

The script continues, but $price and $total are null — later code may produce wrong results. Warnings are signs of bugs and should be fixed, not ignored.


Configuring Error Reporting

Four php.ini settings control what happens with errors:

SettingDevelopmentProductionMeaning
error_reportingE_ALLE_ALLWhich errors are reported at all
display_errorsOnOffWhether errors are shown in the output (browser)
log_errorsOnOnWhether errors are written to the log
error_log(optional)A log file path, e.g. /var/log/php/app-error.logWhere errors are logged (default: the web server's error log or stderr)

Why Different Settings?

  • In development, you want to see every problem immediately, in the browser.
  • In production, error messages can reveal file paths, database names, queries, and code structure to attackers. Errors must be logged for developers but never displayed to visitors (see Error Reporting in Production).

error_reporting should be E_ALL in both environments: hiding warnings in production does not fix them, it only hides the evidence.

Setting Them at Runtime

<?php
error_reporting(E_ALL);
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', __DIR__ . '/../storage/logs/php-error.log');

Settings in php.ini or the server configuration are preferable, because they also apply to errors that occur before your script starts (such as syntax errors in included files).


Preventing Errors Instead of Suppressing Them

Most warnings can be avoided by checking conditions first:

Instead ofWrite
$value = $array['key'];$value = $array['key'] ?? null;
file_get_contents($path) on a file that may be missingis_readable($path) ? file_get_contents($path) : null
strlen($maybeNull)strlen($maybeNull ?? '')
$count = count($maybeArray);$count = is_array($maybeArray) ? count($maybeArray) : 0;

The @ Operator

The error-control operator @ suppresses the display of errors from one expression:

<?php
$content = @file_get_contents('/no/such/file.txt');

var_dump($content);
echo error_get_last()['message'] . "\n";

Output

bool(false)
file_get_contents(/no/such/file.txt): Failed to open stream: No such file or directory

The error still happened — error_get_last() returns it — but it was not displayed or logged. Using @ routinely hides real problems and makes debugging much harder. Prefer checking conditions first, or converting errors into exceptions (see Custom Error Handler). In PHP 8, @ no longer suppresses fatal errors.


Errors That Became Exceptions in PHP 8

Many functions now throw TypeError or ValueError instead of returning false with a warning:

<?php
try {
    array_combine(['a', 'b'], [1]);
} catch (ValueError $e) {
    echo get_class($e) . ": " . $e->getMessage() . "\n";
}

try {
    str_repeat('-', -5);
} catch (ValueError $e) {
    echo get_class($e) . ": " . $e->getMessage() . "\n";
}

Output

ValueError: array_combine(): Argument #1 ($keys) and argument #2 ($values) must have the same number of elements
ValueError: str_repeat(): Argument #2 ($times) must be greater than or equal to 0

These indicate programming mistakes (invalid arguments). They are usually not caught locally; instead, they are fixed in the code. A global handler ensures that, if one slips through, it is logged and the user sees a proper error page.


Handling Uncaught Exceptions Globally

set_exception_handler() registers a function that runs for any exception or Error that is not caught anywhere:

<?php
set_exception_handler(function (Throwable $e): void {
    error_log(sprintf(
        '[%s] %s in %s:%d',
        get_class($e),
        $e->getMessage(),
        $e->getFile(),
        $e->getLine()
    ));

    http_response_code(500);
    echo "Sorry, something went wrong. Please try again later.\n";
});

function loadDashboard(): void
{
    throw new RuntimeException('Database unavailable');
}

loadDashboard();
echo "This line is not reached\n";

Output (what the visitor sees)

Sorry, something went wrong. Please try again later.

What Happens

  1. The exception is not caught, so PHP calls the registered handler.
  2. The handler logs the technical details for developers.
  3. It sends HTTP status 500 and a friendly message — no file paths or internal messages are shown.
  4. After the handler finishes, the script ends.

In a real application, the handler would render a proper error page (and show full details only in development).


Fatal Errors and Shutdown Functions

Some errors — such as exhausting the memory limit or exceeding the maximum execution time — cannot be caught. A shutdown function runs at the very end of every request and can detect them:

<?php
register_shutdown_function(function (): void {
    $error = error_get_last();

    if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
        error_log("Fatal error: {$error['message']} in {$error['file']}:{$error['line']}");

        if (!headers_sent()) {
            http_response_code(500);
        }
        echo "Sorry, something went wrong.";
    }
});

This guarantees that even fatal errors are logged and answered with a proper status code. A complete setup combining error handlers, exception handlers, and shutdown functions is shown in Custom Error Handler.


An Error-Handling Strategy

SituationApproach
Expected problems (missing optional file, invalid user input)Check conditions; return null or validation errors
Failures your code cannot continue from (database down, payment API error)Throw exceptions; catch where you can recover or inform the user
Programming mistakes (TypeError, ValueError, warnings)Fix them; log them if they occur in production
Anything uncaughtGlobal exception handler: log, show a safe error page
Fatal errorsShutdown function: log, send status 500

Common Mistakes

Displaying Errors in Production

Effect: Attackers learn file paths, queries, and configuration details.

Fix: display_errors = Off, log_errors = On in production.

Lowering error_reporting to Hide Warnings

Effect: Bugs remain and become harder to find.

Fix: Keep E_ALL and fix the underlying problems.

Using @ Everywhere

Effect: Failures happen silently.

Fix: Check conditions first or convert errors to exceptions.

Ignoring Deprecation Notices

Effect: Code breaks when upgrading to the next PHP version.

Fix: Log deprecations and fix them regularly (see Migrating to PHP 8).

No Global Handler

Effect: Users see raw error messages or blank pages, and problems are not logged.

Fix: Register exception and shutdown handlers at application startup.


Best Practices

  • Use error_reporting = E_ALL everywhere; display errors only in development.
  • Always log errors in production, and review the logs.
  • Prevent warnings by checking conditions instead of suppressing them.
  • Use exceptions for failures and install global handlers for anything uncaught.
  • Treat warnings and deprecations as bugs to be fixed.

Official reference: https://www.php.net/manual/en/language.errors.php

0 Comments

Reviewed before they appear

No comments yet.

PHP
PHP Home PHP Switch PHP Match Alternative Syntax PHP Loops While Loop Do While Loop For Loop Foreach Loop Nested Loops Break Statement PHP Home PHP Intro PHP Install PHP Built-in Web Server PHP Syntax PHP Tags PHP and HTML PHP Comments PHP Multiline Comments PHP Variables Variables Scope PHP Casting Logical Operators Null Coalescing Operator Spaceship Operator Operator Precedence Continue Statement Modify Strings PHP If...Else...Elseif PHP If Modify Strings PHP If Operators PHP Functions Concatenate Strings PHP If...Else Slicing Strings User-defined Functions Slicing Strings PHP Shorthand if Escape Characters Default Argument Values PHP Nested if Pass by Reference String Interpolation Named Arguments PHP File Upload Variadic Functions Return Values Search in Strings Multibyte Strings Type Declarations in Functions PHP Numbers PHP Math PHP Floats PHP Random Numbers PHP Constants PHP Properties PHP Methods PHP Constructor Constructor Property Promotion PHP Cookies PHP Destructor PHP Access Modifiers Readonly Properties PHP Sessions PHP Inheritance Method Overriding PHP Filters The final Keyword CSRF Protection PHP Filters Advanced Session Security Secure Cookies PHP Magic Constants File Upload Security PHP Callback Functions PHP Operators Filesystem Security PHP JSON Arithmetic Operators Error Reporting in Production Hiding PHP Assignment Operators PHP Configuration (php.ini) Comparison Operators PHP Command Line (CLI) PHP Exceptions Increment / Decrement Operators Migrating to PHP 8 PHP Form Validation PHP Form Required PHP Form URL/E-mail Error Handling Form Input Sanitizing Escaping Output (htmlspecialchars) Custom Error Handler Checkbox, Radio and Select Inputs Sticky Forms PHP Form Complete PHP Date and Time Date Formatting Error Logging HTTP Headers and Redirects Output Buffering Sending Email PHP cURL Consuming REST APIs PHP Generators
Ask about this post
AI Ask about this post

Ask questions about Error Handling and get answers drawn from it.

Signed-in readers only.