PHP Exception Handling
Exceptions are used to change the normal flow of a script if a specified error occurs.
What is an Exception
With PHP 5 came a new object oriented way of dealing with errors.
Exception handling is used to change the normal flow of the code execution if a specified error (exceptional) condition occurs. This condition is called an exception.
This is what normally happens when an exception is triggered:
- The current code state is saved
- The code execution will switch to a predefined (custom) exception handler function
- Depending on the situation, the handler may then resume the execution from the saved code state, terminate the script execution or continue the script from a different location in the code
We will show different error handling methods:
- Basic use of Exceptions
- Creating a custom exception handler
- Multiple exceptions
- Re-throwing an exception
- Setting a top level exception handler
Note: Exceptions should only be used with error conditions, and should not be used to jump to another place in the code at a specified point.
Basic Use of Exceptions
When an exception is thrown, the code following it will not be executed, and PHP will try to find the matching "catch" block.
If an exception is not caught, a fatal error will be issued with an "Uncaught Exception" message.
Lets try to 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);
?>
The code above will get an error like this:
Try, throw and catch
To avoid the error from the example above, we need to create the proper code to handle an exception.
Proper exception code should include:
- try — A function using an exception should be in a "try" block. If the exception does not trigger, the code will continue as normal. However if the exception triggers, an exception is "thrown"
- throw — This is how you trigger an exception. Each "throw" must have at least one "catch"
- catch — A "catch" block retrieves an exception and creates an object containing the exception information
Lets try to trigger an exception with valid code:
<?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();
>
?>
The code above will get an error like this:
Example explained:
The code above throws an exception and catches it:
- The checkNum() function is created. It checks if a number is greater than 1. If it is, an exception is thrown
- The checkNum() function is called in a "try" block
- The exception within the checkNum() function is thrown
- The "catch" block retrieves the exception and creates an object ($e) containing the exception information
- The error message from the exception is echoed by calling $e->getMessage() from the exception object
However, one way to get around the "every throw must have a catch" rule is to set a top level exception handler to handle errors that slip through.
Creating a Custom Exception Class
To create a custom exception handler you must create a special class with functions that can be called when an exception occurs in PHP. The class must be an extension of the exception class.
The custom exception class inherits the properties from PHP’s exception class and you can add custom functions to it.
Lets create an exception class:
<?php
class customException extends Exception <
public function errorMessage() <
//error message
$errorMsg = ‘Error on line ‘.$this->getLine().’ in ‘.$this->getFile()
.’: <b>’.$this->getMessage().'</b> is not a valid E-Mail address’;
return $errorMsg;
>
>
$email = "someone@example. com";
try <
//check if
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();
>
?>
The new class is a copy of the old exception class with an addition of the errorMessage() function. Since it is a copy of the old class, and it inherits the properties and methods from the old class, we can use the exception class methods like getLine() and getFile() and getMessage().
Example explained:
The code above throws an exception and catches it with a custom exception class:
- The customException() class is created as an extension of the old exception class. This way it inherits all methods and properties from the old exception class
- The errorMessage() function is created. This function returns an error message if an e-mail address is invalid
- The $email variable is set to a string that is not a valid e-mail address
- The "try" block is executed and an exception is thrown since the e-mail address is invalid
- The "catch" block catches the exception and displays the error message
Multiple Exceptions
It is possible for a script to use multiple exceptions to check for multiple conditions.
It is possible to use several if..else blocks, a switch, or nest multiple exceptions. These exceptions can use different exception classes and return different error messages:
<?php
class customException extends Exception <
public function errorMessage() <
//error message
$errorMsg = ‘Error on line ‘.$this->getLine().’ in ‘.$this->getFile()
.’: <b>’.$this->getMessage().'</b> is not a valid E-Mail address’;
return $errorMsg;
>
>
try <
//check if
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) <
//throw exception if email is not valid
throw new customException($email);
>
//check for "example" in mail address
if(strpos($email, "example") !== FALSE) <
throw new Exception("$email is an example e-mail");
>
>
catch (customException $e) <
echo $e->errorMessage();
>
Example explained:
The code above tests two conditions and throws an exception if any of the conditions are not met:
- The customException() class is created as an extension of the old exception class. This way it inherits all methods and properties from the old exception class
- The errorMessage() function is created. This function returns an error message if an e-mail address is invalid
- The $email variable is set to a string that is a valid e-mail address, but contains the string "example"
- The "try" block is executed and an exception is not thrown on the first condition
- The second condition triggers an exception since the e-mail contains the string "example"
- The "catch" block catches the exception and displays the correct error message
If the exception thrown were of the class customException and there were no customException catch, only the base exception catch, the exception would be handled there.
Re-throwing Exceptions
Sometimes, when an exception is thrown, you may wish to handle it differently than the standard way. It is possible to throw an exception a second time within a "catch" block.
A script should hide system errors from users. System errors may be important for the coder, but are of no interest to the user. To make things easier for the user you can re-throw the exception with a user friendly message:
<?php
class customException extends Exception <
public function errorMessage() <
//error message
$errorMsg = $this->getMessage().’ is not a valid E-Mail address.’;
return $errorMsg;
>
>
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();
>
?>
Example explained:
The code above tests if the email-address contains the string "example" in it, if it does, the exception is re-thrown:
- The customException() class is created as an extension of the old exception class. This way it inherits all methods and properties from the old exception class
- The errorMessage() function is created. This function returns an error message if an e-mail address is invalid
- The $email variable is set to a string that is a valid e-mail address, but contains the string "example"
- The "try" block contains another "try" block to make it possible to re-throw the exception
- The exception is triggered since the e-mail contains the string "example"
- The "catch" block catches the exception and re-throws a "customException"
- The "customException" is caught and displays an error message
If the exception is not caught in its current «try» block, it will search for a catch block on "higher levels".
Set a Top Level Exception Handler
The set_exception_handler() function sets a user-defined function to handle all uncaught exceptions:
<?php
function myException($exception) <
echo "<b>Exception:</b> " . $exception->getMessage();
>
throw new Exception(‘Uncaught Exception occurred’);
?>
The output of the code above should be something like this:
In the code above there was no "catch" block. Instead, the top level exception handler triggered. This function should be used to catch uncaught exceptions.
Обработка исключений
В процессе работы программы могут возникать различные ошибки, которые могут прервать работу программы. Например, рассмотрим следующую ситуацию:
Программа выводит результат деления. Поскольку делитель равен 0, а на ноль делить нельзя, то при выполнении деления программа завершится, и в браузере мы увидим что-то типа следующего:
Браузер отобразит нам произошедшую ошибку, причем дальше после строки с делением программа даже не будет выполняться.
Кто-то может сказать, что ситуация искуственная, так как мы сами определили делитель равный нулю. Но данные могут передаваться извне. Кроме того, кроме деления на ноль есть различные ситуации, при которых могут происходить ошибки. Но PHP предоставляет ряд возможностей для обработки подобных ситуаций.
Для обработки исключений в PHP применяется конструкция try-catch :
Эта конструкция в общем варианте состоит из двух блоков — try и catch . В блок try помещается код, который потенциально может вызвать исключение. А в блоке catch помещается обработка возникшего исключения. Причем каждого типа исключения мы можем определить свою логику обработки. Конкретный тип исключения, который мы хотим обработать, указывается в круглых скобках после оператора catch :
После названия типа указывается переменная этого типа (в данном случае $ex ), которая будет хранить информацию об исключении и которую мы можем использовать при обработке исключения.
Если в блоке try при выполнении кода возникает ошибка, то блок try прекращает выполнение и передает управление блоку catch , который обрабатывает ошибку. А после завершения выполнения кода в блоке catch программа продолжает выполнять инструкции, которые размещены после блока catch .
Если в блоке try при выполнении кода не возникает ошибок, то блок catch не выполняется, а после завершения блока try программа продолжает выполнять инструкции, которые размещены после блока catch .
Например, обработаем ошибку с делением на ноль:
В данном случае код деления на ноль, поскольку он может потенциально вызвать ошибку, помещен в блок try .
В блоке catch обрабатывается ошибка типа DivisionByZeroError , которая генерируется при делении на ноль. Вся обработка сводится к выводу информации на экран.
В итоге при выполнении программа выведет следующее:
Как видно из вывода программы, она не завершается аварийно при делении на ноль, а продолжает работу.
Типы ошибок и исключений
В PHP для разных ситуаций есть множество типов, которые описывают ошибки. Все эти встроенные типы применяют интерфейс Throwable :

Все типы делятся на две группы: собственно ошибки (класс Error ) и собственно исключения (класс Exception ). А от классов Error и Exception наследуются классы ошибок и исключений, которые описывают конкретные ситуации. Например, от класса Error наследуется класс ArithmeticError , который описывает ошибки, возникающие при выполнении арифметических операций. А от класса ArithmeticError наследуется класс DivisionByZeroError , который представляют ошибку при делении на ноль.
Блок catch
Конструкция try..catch позволяет определить несколько блоков catch — для обработки различных типов ошибок и исключений:
При возникновении ошибки будет для ее обработки будет выбираться тот блок catch , который соответствует вошникшей ошибки. Так, в данном случае при делении на ноль будет выполняться второй блок catch .
Если бы в блоке try возникла бы ошибка, которая бы не соответствовала типам из блоков catch (в данном случае — типам DivisionByZeroError и ParseError), то такая ошибка не была бы обработана, и соответственно программа бы аварийно завершила свое выполнение.
Блоки catch с более конкретными типами ошибок и исключений должны идти в начале, а более с более общими типа — в конце:
Класс DivisionByZeroError унаследован от ArithmeticError, который, в свою очередь, унаследован от Error, реализующего интерфейс Throwable. Поэтому класс DivisionByZeroError представляет более конкретный тип и представляемые им ошибки должны обрабатываться в первую очередь. А тип Throwable представляет наиболее общий тип, так как ему соответствуют все возможные ошибки и исключения, поэтому блоки catch с таким типом должны идти в конце.
В данном случае опять же в блоке try происходит ошибка деления на ноль. Но этой ошибке соответствуют все четыре блока catch . Для обработки PHP будет выбирать первый попавшийся, который соответствует типу ошибки. В данном случае это блок для обработки ошибки типа DivisionByZeroError.
Если нам надо обрабатывать в принципе все ошибки и исключения, то мы можем определить только обработку общего для всех них типа Throwable:
Начиная с версии PHP 8.0 в блоке catch можно просто указать тип обрабатываемого исключения, не определяя переменную:
Получение информации об ошибках и исключениях
Интерфейс Throwable предоставляет ряд методов, которые позволяют получить некоторую информацию о возникшем исключении:
getMessage() : возвращает сообщение об ошибке
getCode() : возвращает код исключения
getFile() : возвращает название файла, в котором возникла ошибка
getLine() : возвращает номер строки, в которой возникла ошибка
getTrace() : возвращает трассировку стека
getTraceAsString() : возвращает трассировку стека в виде строки
Применим некоторые из этих методов:
Блок finally
Конструкция try..catch также может определять блок finally . Этот блок выполняется в конце — после блока try и catch вне зависимости, возникла или нет ошибка. Нередко блок finally используется для закрытия ресурсов, которые применяются в блоке try.
Конструкция try..catch..finally может содержать либо все три блока, либо только два блока try и либо блок catch , либо блок finally .
PHP try…catch
Summary: in this tutorial, you will learn how to use the PHP try. catch statement to handle exceptions.
Introduction to the PHP try…catch statement
In programming, unexpected errors are called exceptions. Exceptions can be attempting to read a file that doesn’t exist or connecting to the database server that is currently down.
Instead of halting the script, you can handle the exceptions gracefully. This is known exception handling.
To handle the exceptions, you use the try. catch statement. Here’s a typical syntax of the try. catch statement:
In this syntax, the try. catch statement has two blocks: try and catch .
In the try block, you do some tasks e.g.,reading a file. If an exception occurs, the execution jumps to the catch block.
In the catch block, you specify the exception name and the code to handle a specific exception.
PHP try…catch example
The following example shows how to read data from a CSV file:
If the data.csv file doesn’t exist, you’ll get many warrnings. The following shows the first warning:
To fix this, you may add an if statement in every step:
However, this code mixes the program logic and error handlers.
The advantage of the try. catch statement is to separate the program logic from the error handlers. Therefore, it makes code easier to follow.
The following illustrates how to use the try. catch block for reading data from a CSV file:
In this example, if any error occurs in the try. block , the execution jumps to the catch block.
The exception variable $ex is an instance of the Exception class that contains the detailed information of the error. In this example, we get the detailed error message by calling the getMessage() method of the $ex object.
Multiple catch blocks
A try. catch statement can have multiple catch blocks. Each catch block will handle a specific exception:
When a try. catch statement has multiple catch blocks, the order of exception should be from the specific to generic. And the last catch block should contain the code for handling the most generic exception. By doing this, the try. catch statement can catch all the exceptions.
If you have the same code that handles multiple types of exceptions, you can place multiple exceptions in one catch block and separate them by the pipe ( | ) character like this:
By specifying multiple exceptions in the catch block, you can avoid code duplication. This feature has been supported since PHP 7.1.0.
Ignoring the exception variable
As of PHP 8.0, the variable name for the caught exception is optional like this:
In this case, the catch block will still execute but won’t have access the Exception object.
Исключения
В PHP реализована модель исключений, аналогичная тем, что используются в других языках программирования. Исключение в PHP может быть выброшено ( throw ) и поймано ( catch ). Код может быть заключён в блок try , чтобы облегчить обработку потенциальных исключений. У каждого блока try должен быть как минимум один соответствующий блок catch или finally .
Если выброшено исключение, а в текущей области видимости функции нет блока catch , исключение будет "подниматься" по стеку вызовов к вызывающей функции, пока не найдёт подходящий блок catch . Все блоки finally , которые встретятся на этом пути, будут выполнены. Если стек вызовов разворачивается до глобальной области видимости, не встречая подходящего блока catch , программа завершается с неисправимой ошибкой, если не был установлен глобальный обработчик исключений.
Выброшенный объект должен наследовать ( instanceof ) интерфейс Throwable . Попытка выбросить объект, который таковым не является, приведёт к неисправимой ошибке PHP.
Начиная с PHP 8.0.0, ключевое слово throw является выражением и может быть использовано в любом контексте выражения. В предыдущих версиях оно было утверждением и должно было располагаться в отдельной строке.
catch
Блок catch определяет, как реагировать на выброшенное исключение. Блок catch определяет один или несколько типов исключений или ошибок, которые он может обработать, и, по желанию, переменную, которой можно присвоить исключение (указание переменной было обязательно до версии PHP 8.0.0). Первый блок catch , с которым столкнётся выброшенное исключение или ошибка и соответствует типу выброшенного объекта, обработает объект.
Несколько блоков catch могут быть использованы для перехвата различных классов исключений. Нормальное выполнение (когда исключение не выброшено в блоке try ) будет продолжаться после последнего блока catch , определённого в последовательности. Исключения могут быть выброшены ( throw ) (или повторно выброшены) внутри блока catch . В противном случае выполнение будет продолжено после блока catch , который был вызван.
При возникновении исключения, код, следующий за утверждением, не будет выполнен, а PHP попытается найти первый подходящий блок catch . Если исключение не поймано, будет выдана неисправимая ошибка PHP с сообщением " Uncaught Exception . ", если только обработчик не был определён с помощью функции set_exception_handler() .
Начиная с версии PHP 7.1.0, в блоке catch можно указывать несколько исключений, используя символ | . Это полезно, когда разные исключения из разных иерархий классов обрабатываются одинаково.
Начиная с версии PHP 8.0.0, имя переменной для пойманного исключения является необязательным. Если оно не указано, блок catch будет выполнен, но не будет иметь доступа к выброшенному объекту.
finally
Блок finally также может быть указан после или вместо блоков catch . Код в блоке finally всегда будет выполняться после блоков try и catch , независимо от того, было ли выброшено исключение и до возобновления нормального выполнения.
Одно из заметных взаимодействий происходит между блоком finally и оператором return . Если оператор return встречается внутри блоков try или catch , блок finally всё равно будет выполнен. Более того, оператор return выполнится, когда встретится, но результат будет возвращён после выполнения блока finally . Кроме того, если блок finally также содержит оператор return , возвращается значение из блока finally .
Глобальный обработчик исключений
Если исключению разрешено распространяться на глобальную область видимости, оно может быть перехвачено глобальным обработчиком исключений, если он установлен. Функция set_exception_handler() может задать функцию, которая будет вызвана вместо блока catch , если не будет вызван никакой другой блок. Эффект по сути такой же, как если бы вся программа была обёрнута в блок try — catch с этой функцией в качестве catch .
Примечания
Замечание:
Внутренние функции PHP в основном используют отчёт об ошибках, только современные объектно-ориентированные модули используют исключения. Однако ошибки можно легко перевести в исключения с помощью класса ErrorException. Однако эта техника работает только с исправляемыми ошибками.
Пример #1 Преобразование отчётов об ошибках в исключения
<?php
function exceptions_error_handler ( $severity , $message , $filename , $lineno ) <
throw new ErrorException ( $message , 0 , $severity , $filename , $lineno );
>