Skip to Content
Course content

120: set_error_handler and set_exception_handler

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've spent a lot of time in the past staring at the "White Screen of Death" or, worse, seeing a raw PHP stack trace leaked to a client's browser. It's a nightmare for security and a terrible user experience. Usually, we wrap things in try...catch blocks, but in a large application, you can't possibly wrap every single line of code. You need a global safety net.

Watching the script crash

Let's look at a messy scenario. I'm building a small script that parses a weather API response. I'll intentionally write some brittle code to see how PHP handles it by default.

<?php
// Imagine this comes from an API
$weatherData = ['temp' => 72, 'city' => 'Austin'];

// I'm accessing a key that doesn't exist (Notice)
echo "Humidity: " . $weatherData['humidity'];

// And I'm throwing an exception that isn't caught (Fatal)
throw new Exception("API Connection Timeout!");
?>

If I run this, PHP first gives me a Warning: Undefined array key "humidity" and then it completely halts with an Uncaught Exception. In a local environment, this is helpful. In production, it's a disaster. I want to control how these are reported without cluttering my business logic with a thousand try-catch blocks.

Taming the PHP warnings

First, I want to deal with those annoying notices and warnings. PHP has a function called set_error_handler that lets me intercept these before they hit the screen. Let's try overriding the default behavior.

<?php
function myErrorHandler($errno, $errstr, $errfile, $errline) {
    echo "<p style='color: orange;'>[Log]: Error ($errno) $errstr in $errfile on line $errline</p>";
    // Return true to tell PHP we've handled it; otherwise, it might still trigger the internal handler
    return true; 
}

set_error_handler("myErrorHandler");

$weatherData = ['temp' => 72];
echo $weatherData['humidity']; // This now triggers my custom function
?>

Now, instead of the standard PHP warning, I get my custom orange message. I can now route this to a file, send it to a Slack channel, or just ignore it if it's a non-critical notice. One thing to keep in mind: set_error_handler doesn't catch "Fatal Errors" (like calling a function that doesn't exist). Those are too severe for this handler to intercept.

The safety net for uncaught exceptions

That brings us to the Exception I threw earlier. My error handler didn't touch it because exceptions aren't "errors" in the traditional PHP sense—they are objects. If an exception bubbles all the way up without being caught by a catch block, the script dies.

I can stop the crash by using set_exception_handler. This is basically the "last resort" catch block for the entire application.

<?php
function myExceptionHandler($exception) {
    echo "<h1>Oops! Something went wrong</h1>";
    echo "<p>Technical details: " . $exception->getMessage() . "</p>";
    // In a real app, I'd log the stack trace to a file here
    exit(); 
}

set_exception_handler("myExceptionHandler");

// This will no longer cause a raw PHP crash
throw new Exception("API Connection Timeout!");
?>

I love this approach because it separates my "happy path" logic from my "disaster recovery" logic. My main code just focuses on getting the weather, and these two handlers sit in the background, waiting to clean up the mess if something breaks.

Connecting the two

In a professional setup, you'd usually put these handlers in a bootstrap or config file that loads at the very start of the request. If you want to convert old-school PHP errors into exceptions so you only have to manage one handler, you can actually call error_trigger inside your error handler, or use a library that does this for you. But for most projects, having one handler for warnings/notices and one for uncaught exceptions is the sweet spot for stability.




📋 Practical Task

Building a Unified Crash-Report System for a User Import Script

You are writing a script that imports users from a CSV file. The script is prone to two types of failures: missing data in the CSV (which triggers PHP notices) and database connection failures (which trigger Exceptions).

Your task is to implement a global error and exception handling system with the following requirements:

  • Create a set_error_handler that catches notices/warnings and prints them in a <div> with a red border, prefixing the message with "CSV Data Issue: ".
  • Create a set_exception_handler that catches any uncaught Exception, prints a user-friendly message ("The import process has been halted due to a system error"), and then logs the actual exception message to a file named error_log.txt using file_put_contents().
  • Test your handlers by:
    1. Attempting to access an undefined index in an array.
    2. Throwing a new Exception("Database connection failed!").
Rating
0 0

There are no comments for now.

to be the first to leave a comment.