How To Catch All Errors & Exceptions In PHP

Welcome to a quick tutorial on how to catch all errors and exceptions in PHP. Need to cast a net and capture all the errors to figure out what went wrong?

We can capture all errors in PHP using the set_exception_handler() function. For example:

  • function elog ($ex) { error_log($ex->getMessage()); }
  • set_exception_handler($elog);

That covers the quick basics, but read on if you need a detailed example.

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

Download & Notes Catch All Useful Bits & Links
The End

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

QUICK NOTES

If you spot a bug, please feel free to comment below. I try to answer questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

 

PHP CATCH ALL ERRORS

All right, let us now get into an example of catching all errors and exceptions in PHP.

 

1) THE DEMO DATABASE CLASS

1-db.php
<?php
// (A) DATABASE CLASS
class Database {
  // (A1) PROPERTIES
  protected $pdo;
  protected $stmt;

  // (A2) CONNECT TO DATABASE
  function __construct () {
    $this->pdo = new PDO(
      "mysql:host=". DB_HOST .";charset=". DB_CHARSET .";dbname=". DB_NAME,
      DB_USER, DB_PASSWORD, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, 
        PDO::ATTR_EMULATE_PREPARES => false
      ]
    );
  }

  // (A3) CLOSE DATABASE CONNECTION
  function __destruct () {
    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }

  // (A4) QUERY
  function query ($sql, $data) {
    $this->stmt = $this->pdo->prepare($sql);
    return $this->stmt->execute($data);
  }
}

// (B) DATABASE SETTINGS
define('DB_HOST', 'localhost');
define('DB_NAME', 'doesnotexist');
define('DB_CHARSET', 'utf8');
define('DB_USER', 'root');
define('DB_PASSWORD', '');

// (C) CREATE NEW OBJECT
$dbObj = new Database();

For a start, we have a “normal” class Database here. This will connect to the database when a new Database() object is created, and we can use it to run SQL queries. That’s about it, but the problem is – Some errors and exceptions may still happen, and we want to keep error logs for debugging later.

 

 

2) EXCEPTION HANDLER

2-core.php
<?php
// (A) ERROR HANDLING SETTINGS
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . DIRECTORY_SEPARATOR . 'error.log');
error_reporting(E_ALL & ~E_NOTICE);

// (B) CATCH ALL ERRORS
set_exception_handler(function($ex) {
  error_log($ex->getMessage(), 0);
  error_log($ex->getFile() . " - " . $ex->getLine(), 0);
  error_log($ex->getTraceAsString(), 0);
  echo $ex->getMessage();
});

// (C) NEW DATABASE OBJECT
require "1-db.php";

So here we have the solution. As in the introduction above, we use the set_exception_handler() function to capture all the errors and exceptions – Create a log file or show a “nice error message” if you want.

 

 

EXTRA) THE BAD WAY

3-bad.php
<?php
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . DIRECTORY_SEPARATOR . 'error.log');
error_reporting(E_ALL & ~E_NOTICE);

// (B) "LOADER FUNCTION"
function loader ($scripts) {
  foreach ($scripts as $src) {
    try { require $src; }
    catch (Exception $ex) {
      error_log($ex->getMessage(), 0);
      error_log($ex->getFile() . " - " . $ex->getLine(), 0);
      error_log($ex->getTraceAsString(), 0);
      echo $ex->getMessage();
    }
  }
}

// (C) GO!
loader(["1-db.php", "xyz.php", "abc.php"]);

Once upon a time in the Dark Ages, this is what I actually did. Create a function loader() that will load scripts and wrap them in a try-catch block. Well, it works. But wrapping everything in try-catch is not the smartest way. So I will just leave this here as a “possible but not good alternative”.

 

 

USEFUL BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

INFOGRAPHIC CHEAT SHEET

Catch All Errors In PHP (Click To Enlarge)

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

2 thoughts on “How To Catch All Errors & Exceptions In PHP”

    1. Sorry if this is rude, but that snippet makes very little sense.

      1) Read the tutorial carefully, it is about using set_exception_handler() to capture all errors and handle them accordingly.
      2) The error message can be obtained from the exception itself – $ex->getMessage(). Also the file $ex->getFile(), line $ex->getLine(), and stack trace $ex->getTraceAsString().
      3) Notice how I deliberately left out the PHP error code $ex->getCode()? That’s how little value it provided for debugging in years of my web development career. If you need it somehow – https://www.php.net/manual/en/errorfunc.constants.php
      4) BAD idea to display the full error message, code, script name, and line number on a live system. Huge security risk.
      5) Just show a simple “an error has occurred” to the user where possible. Or just the error message without file name, line, trace, and error code.
      6) Keep error details internal – In a log file, or automatically send an email on critical stops.
      7) What’s the point of glorifying the error details in a popup box? Are jQuery and Bootstrap really necessary? If you want to show an error on the screen, just do a <?=$ex->getMessage()?>.

      P.S. The error code is not totally useless. It can still be used for “graceful failures” such as shutting down on critical errors – if (CODE == 4096) { SHUT DOWN }.

Leave a Comment

Your email address will not be published. Required fields are marked *