Learning Objectives – after this chapter you will be able to:
- Handle errors with
die(), custom error handlers andtrigger_error(). - Know PHP's error report levels and configure error reporting and logging.
- Send error messages by e-mail with
error_log(). - Use exceptions:
try,throw,catch,finally, custom exception classes, multiple catches and re-throwing. - Set a top-level exception handler and understand PHP 8's
Error/Throwablehierarchy.
PHP Error Handling
The default error handling in PHP is very simple: an error message with the file name, line number and a description of the error is sent to the browser.
When creating scripts and web applications, error handling is an important part. If your code lacks error-checking, your program may look very unprofessional and you may be open to security risks (error messages can reveal file paths and other internal details). This chapter shows different error-handling methods:
- Simple
die()statements - Custom errors and error triggers
- Error reporting and logging
- Exceptions
Basic Error Handling – die()
The first example simply opens a text file:
<?php
$file = fopen("welcome.txt", "r");
?>Warning: fopen(welcome.txt): Failed to open stream: No such file or directory in /opt/lampp/htdocs/phpbook/ch20/open1.php on line 2
If the file does not exist you get a warning like the one above. To prevent the user from seeing such a message, test whether the file exists before trying to access it:
<?php
if (!file_exists("welcome.txt")) {
die("File not found");
} else {
$file = fopen("welcome.txt", "r");
}
?>File not found
This is better than the earlier code because it uses a simple error-handling mechanism to stop the script after the error. However, simply stopping the script is not always the right way. Let us look at alternative functions for handling errors.
Creating a Custom Error Handler
Creating a custom error handler is quite simple: we write a special function that is called when an error occurs. The function must accept at least two parameters (the error level and the error message) and can accept up to four (optionally the file and the line number):
error_function(error_level, error_message, error_file, error_line)
| Parameter | Description |
|---|---|
| error_level | Required. The error report level of the error – a number (see the table below). |
| error_message | Required. The error message. |
| error_file | Optional. The file name in which the error occurred. |
| error_line | Optional. The line number on which the error occurred. |
PHP 5 passed a fifth parameter, error_context (an array of all variables in scope). It was deprecated in PHP 7.2 and is no longer passed in PHP 8.
Error report levels
| Value | Constant | Description |
|---|---|---|
| 1 | E_ERROR | Fatal run-time error. Execution of the script is halted. |
| 2 | E_WARNING | Non-fatal run-time error. Execution is not halted. (In PHP 8 "Undefined variable" is a warning.) |
| 4 | E_PARSE | Compile-time parse (syntax) error. |
| 8 | E_NOTICE | Run-time notice – something that might be an error. |
| 256 | E_USER_ERROR | Fatal user-generated error, set with trigger_error(). |
| 512 | E_USER_WARNING | Non-fatal user-generated warning. |
| 1024 | E_USER_NOTICE | User-generated notice (the default of trigger_error()). |
| 2048 | E_STRICT | Suggestions for better code (part of E_ALL since PHP 5.4). |
| 4096 | E_RECOVERABLE_ERROR | Catchable fatal error. |
| 8192 | E_DEPRECATED | Use of features that will be removed in future versions. |
| 32767 | E_ALL | All errors and warnings (the value in PHP 8). |
Now let us create a function to handle errors:
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br>";
echo "Ending Script";
die();
}It receives the error level and message, prints them and ends the script.
Setting the Error Handler
PHP's default error handler is the built-in one. set_error_handler() makes our function the default for the rest of the script. A second parameter can restrict it to certain error levels; here we handle all errors. We test it by printing a variable that does not exist:
<?php
// error handler function
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr";
}
// set error handler
set_error_handler("customError");
// trigger error
echo($test);
?>Error: [2] Undefined variable $test
(In PHP 7 this was a notice, level 8; PHP 8 raised "Undefined variable" to a warning, level 2.)
Triggering an Error
In a script where users enter data, it is useful to trigger errors when illegal input occurs. In PHP this is done with trigger_error(). In this example an error occurs if the $test variable is bigger than 1:
<?php
$test = 2;
if ($test > 1) {
trigger_error("Value must be 1 or below");
}
echo "<br>Script continues after a notice.";
?>Notice: Value must be 1 or below in /opt/lampp/htdocs/phpbook/ch20/trigger.php on line 4 Script continues after a notice.
An error can be triggered anywhere in a script, and a second parameter specifies the level:
- E_USER_ERROR – fatal user-generated run-time error; execution is halted.
- E_USER_WARNING – non-fatal user-generated warning; execution continues.
- E_USER_NOTICE – the default; a user-generated notice.
In the next example an E_USER_WARNING occurs if $test is bigger than 1; our custom handler then ends the script:
<?php
// error handler function
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br>";
echo "Ending Script";
die();
}
// set error handler only for E_USER_WARNING
set_error_handler("customError", E_USER_WARNING);
// trigger error
$test = 2;
if ($test > 1) {
trigger_error("Value must be 1 or below", E_USER_WARNING);
}
?>Error: [512] Value must be 1 or below Ending Script
Error Reporting and Logging
Which errors are reported and where they go is controlled in php.ini or at run time:
error_reporting = E_ALL display_errors = On ; show errors in the browser – development only log_errors = On error_log = "C:\xampp\php\logs\php_error_log"
On a production server set display_errors = Off and keep log_errors = On, so visitors never see internal details but you can read them in the log. In a script, error_reporting(E_ALL & ~E_NOTICE) or ini_set('display_errors', '0') change the settings for that script only.
Sending an error message by e-mail
By default PHP sends errors to the server's logging system or a file, depending on the error_log setting. With the error_log() function you can send a message to a specific file or a remote destination. Sending error messages to yourself by e-mail is a good way of being notified of specific errors:
error_log(message, message_type, destination, extra_headers) // message_type: 0 = system log, 1 = e-mail, 3 = append to a file, 4 = SAPI handler
<?php
// error handler function
function customError($errno, $errstr)
{
echo "<b>Error:</b> [$errno] $errstr<br>";
echo "Webmaster has been notified";
error_log("Error: [$errno] $errstr", 1,
"someone@example.com", "From: webmaster@example.com");
}
// set error handler
set_error_handler("customError", E_USER_WARNING);
// trigger error
$test = 2;
if ($test > 1) {
trigger_error("Value must be 1 or below", E_USER_WARNING);
}
?>Error: [512] Value must be 1 or below Webmaster has been notified
The mail received from the code above contains: Error: [512] Value must be 1 or below. This should not be used for all errors – regular errors should be logged on the server with the default PHP logging system.
<?php
error_log(date("Y-m-d H:i:s") . " Login failed for user 'guest'\n", 3, "app_errors.log");
error_log(date("Y-m-d H:i:s") . " Payment gateway timeout\n", 3, "app_errors.log");
echo "Log file contents:<pre>" . file_get_contents("app_errors.log") . "</pre>";
?>Log file contents: 2026-10-22 12:10:21 Login failed for user 'guest' 2026-10-22 12:10:21 Payment gateway timeout
Exceptions
Exceptions are used to change the normal flow of a script if a specified error (exceptional condition) occurs. With PHP 5 came this object-oriented way of dealing with errors. When an exception is triggered, normally:
- The current code state is saved.
- Code execution switches to a predefined (custom) exception handler.
- Depending on the situation, the handler may resume execution from the saved state, terminate the script, or continue from a different location in the code.
Exceptions should only be used for error conditions, not as a way to jump to another place in the code.
Basic use of exceptions
When an exception is thrown, the code following it is not executed, and PHP looks for the matching catch block. If an exception is not caught, a fatal error with an "Uncaught Exception" message is issued. Let us throw an exception without catching it:
<?php
// create function with an exception
function checkNum($number)
{
if ($number > 1) {
throw new Exception("Value must be 1 or below");
}
return true;
}
// trigger exception
checkNum(2);
?>Fatal error: Uncaught Exception: Value must be 1 or below in /opt/lampp/htdocs/phpbook/ch20/uncaught.php:6 Stack trace: #0 /opt/lampp/htdocs/phpbook/ch20/uncaught.php(11): checkNum() #1 {main} thrown in /opt/lampp/htdocs/phpbook/ch20/uncaught.php on line 6try, throw and catch
To avoid the error above, write proper exception-handling code:
- try – a function that may throw an exception is called inside a
tryblock. If no exception is triggered, the code continues as normal; if it is, the exception is "thrown". - throw – this is how you trigger an exception. Each
throwshould have at least onecatch. - catch – a
catchblock retrieves an exception and receives an object containing the exception information. - finally (PHP 5.5) – a block that always runs after
try/catch, whether or not an exception occurred; used for clean-up.
<?php
// create function with an exception
function checkNum($number)
{
if ($number > 1) {
throw new Exception("Value must be 1 or below");
}
return true;
}
// trigger exception in a "try" block
try {
checkNum(2);
// If the exception is thrown, this text will not be shown
echo 'If you see this, the number is 1 or below';
}
// catch exception
catch (Exception $e) {
echo 'Message: ' . $e->getMessage() . "<br>";
echo 'Line: ' . $e->getLine();
}
finally {
echo "<br>finally block: always executed";
}
?>Message: Value must be 1 or below Line: 6 finally block: always executed
Example explained:
- The
checkNum()function checks whether a number is greater than 1. If it is, an exception is thrown. checkNum()is called inside atryblock, and the exception is thrown.- The
catchblock retrieves the exception and creates an object$econtaining the exception information. - The error message is printed by calling
$e->getMessage();getLine(),getFile(),getCode()andgetTraceAsString()give more details.
Creating a Custom Exception Class
To create a custom exception, write a class that extends PHP's Exception class. It inherits all properties and methods of Exception, and you can add your own functions.
<?php
class customException extends Exception
{
public function errorMessage()
{
// error message
$errorMsg = 'Error on line ' . $this->getLine() . ' in ' . basename($this->getFile())
. ': <b>' . $this->getMessage() . '</b> is not a valid E-Mail address';
return $errorMsg;
}
}
$email = "someone@example...com";
try {
// check if the address is valid
if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
// throw exception if email is not valid
throw new customException($email);
}
} catch (customException $e) {
// display custom message
echo $e->errorMessage();
}
?>Error on line 17 in customex.php: someone@example...com is not a valid E-Mail address
The new class is a copy of the old exception class with an added errorMessage() function. Because it inherits from Exception, we can use methods such as getLine(), getFile() and getMessage().
Multiple Exceptions
A script can use several exceptions to check several conditions, with different exception classes returning different error messages:
<?php
class customException extends Exception
{
public function errorMessage()
{
return 'Error on line ' . $this->getLine() . ' in ' . basename($this->getFile())
. ': <b>' . $this->getMessage() . '</b> is not a valid E-Mail address';
}
}
$email = "someone@example.com";
try {
// check if the address is valid
if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
throw new customException($email);
}
// check for "example" in the mail address
if (strpos($email, "example") !== FALSE) {
throw new Exception("$email is an example e-mail");
}
} catch (customException $e) {
echo $e->errorMessage();
} catch (Exception $e) {
echo $e->getMessage();
}
?>someone@example.com is an example e-mail
The address is valid, so the first condition does not throw; the second condition throws a normal Exception because the address contains "example", and the second catch block handles it. If there were no customException catch, only the base Exception catch, the exception would be handled there. Since PHP 7.1 one block can catch several types: catch (TypeA | TypeB $e).
Re-throwing Exceptions
Sometimes you want to handle an exception differently from the standard way. It is possible to throw an exception a second time inside a catch block. A script should hide system errors from users: system errors matter to the programmer but not to the user, so you can re-throw the exception with a user-friendly message.
<?php
class customException extends Exception
{
public function errorMessage()
{
return $this->getMessage() . ' is not a valid E-Mail address.';
}
}
$email = "someone@example.com";
try {
try {
// check for "example" in mail address
if (strpos($email, "example") !== FALSE) {
// throw exception if email is not valid
throw new Exception($email);
}
} catch (Exception $e) {
// re-throw exception
throw new customException($email);
}
} catch (customException $e) {
// display custom message
echo $e->errorMessage();
}
?>someone@example.com is not a valid E-Mail address.
If an exception is not caught in its current try block, PHP looks for a catch block on "higher levels".
Setting a Top-Level Exception Handler
set_exception_handler() sets a user-defined function to handle all uncaught exceptions:
<?php
function myException($exception)
{
echo "<b>Exception:</b> " . $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
?>Exception: Uncaught Exception occurred
There is no catch block in this code; instead the top-level exception handler is triggered. Use it to catch exceptions that slip through everything else (and, for example, log them and show a friendly page).
Errors as Exceptions in PHP 8
Since PHP 7, most fatal errors are thrown as objects of the class Error, so they can be caught too. Both Exception and Error implement the interface Throwable:
Throwable ├── Exception (RuntimeException, InvalidArgumentException, mysqli_sql_exception, …) └── Error (TypeError, ValueError, ArithmeticError → DivisionByZeroError, …)
<?php
function divide(int $a, int $b): int
{
return intdiv($a, $b);
}
try {
echo divide(10, 0);
} catch (DivisionByZeroError $e) {
echo get_class($e) . ": " . $e->getMessage() . "<br>";
}
try {
echo strlen(); // wrong number of arguments
} catch (Throwable $t) {
echo get_class($t) . ": " . $t->getMessage();
}
?>DivisionByZeroError: Division by zero ArgumentCountError: strlen() expects exactly 1 argument, 0 given
Rules for Exceptions
- Code may be surrounded by a
tryblock to help catch potential exceptions. - Each
tryblock orthrowmust have at least one correspondingcatch(orfinally) block. - Multiple
catchblocks can be used to catch different classes of exceptions. - Exceptions can be thrown (or re-thrown) in a
catchblock within atryblock. - A simple rule: if you throw something, you have to catch it.
Key Takeaways
die()/exit()stop a script with a message; check conditions such asfile_exists()first.set_error_handler()installs a custom function receiving level, message, file and line.trigger_error()raises E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR.- In production:
display_errors = Off,log_errors = On;error_log()writes to a log, a file or e-mail. - Exceptions:
try/throw/catch/finally; extendExceptionfor custom types; catch several types; re-throw with friendly messages. set_exception_handler()handles uncaught exceptions; PHP 8 throwsErrorobjects – catchThrowablefor both.
Program File
Extract the ZIP into C:\xampp\htdocs. It creates the folder phpbook/ch20 used in the file labels above; open the programs at http://localhost/phpbook/… with Apache (and MySQL, where needed) started in the XAMPP Control Panel.
Question / Answer (15 questions)
MCQ Test : Check Your Understanding (5 questions)
Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.
Bibliography/References
The notes on this page are the author’s own compilation from the e-book PHP: Basics to Advance. Every program was run on Apache with PHP 8 and MariaDB, and the output shown is the real result of that run. The works listed below were consulted and are cited for attribution and further reading. Product names and trademarks belong to their respective owners.
- The PHP Group. (n.d.). PHP Manual – Error Handling and Logging. https://www.php.net/manual/en/book.errorfunc.php
- The PHP Group. (n.d.). PHP Manual – Predefined Constants (error levels). https://www.php.net/manual/en/errorfunc.constants.php
- The PHP Group. (n.d.). PHP Manual – set_error_handler. https://www.php.net/manual/en/function.set-error-handler.php
- The PHP Group. (n.d.). PHP Manual – Exceptions. https://www.php.net/manual/en/language.exceptions.php
- The PHP Group. (n.d.). PHP Manual – Errors in PHP 7. https://www.php.net/manual/en/language.errors.php7.php