- PHP try…catch…finally
- Introduction to the PHP try…catch…finally statement
- PHP finally & return
- The try…finally statement
- Summary
- Обработка исключений
- Типы ошибок и исключений
- Блок catch
- Получение информации об ошибках и исключениях
- Блок finally
- Try Catch PHP или исключения в PHP
- Когда используются исключения?
- Нужно ли перехватывать все исключения?
PHP try…catch…finally
Summary: in this tutorial, you’ll learn how to use the PHP try. catch. finally statement to handle exceptions and clean up the resources.
Introduction to the PHP try…catch…finally statement
The try…catch statement allows you to handle exceptions. When an exception occurs in the try block, the execution jumps to the catch block. In the catch block, you can place the code that handles the exception.
The following example uses the try…catch block to read a CSV file into an array:
$data = []; try < $f = fopen('data.csv', 'r'); while ($row = $fgetcsv($f)) < $data[] = $row; >fclose($f); > catch (Exception $ex) < echo $ex->getMessage(); >
Code language: HTML, XML (xml)
In this example, if an error occurs while reading the file, the execution jumps to the catch block. Therefore, the following statement will never run:
fclose($f);
Code language: PHP (php)
When the file is not closed properply, it may be inaccessible later.
To ensure that the file will be closed properly regardless of whatever exception occurs or not, you can close the file in the finally block like this:
$data = []; try < $f = fopen('data.csv', 'r'); while ($row = $fgetcsv($f)) < $data[] = $row; >> catch (Exception $ex) < echo $ex->getMessage(); > finally < if ($f) < fclose($f); >>
Code language: HTML, XML (xml)
The finally is an optional block of the try…catch statement. The finally block always executes after the try or catch block.
In this case, if an exception occurs while reading the file, the execution jumps to the catch block to handle it and then the finally block executes to close the file.
The syntax of the try. catch. finally block is as follows:
try < // do something > catch (Exception $e) < // code to handle exception > finally < // code to clean up the resource >
Code language: HTML, XML (xml)
PHP finally & return
The following defines the divide() function that returns the division of two numbers. If an error occurs, it returns null .
function divide($x, $y) < try < $result = $x / $y; return $result; > catch (Exception $e) < return null; > finally < return null; > >
Code language: HTML, XML (xml)
However, the following displays NULL instead of 5:
// . $result = divide(10, 2); var_dump($result); // NULL
Code language: HTML, XML (xml)
Typically, the return statement immediately stops the execution and returns a value. However, it doesn’t work that way when it is used with the try. catch. finally statement.
When you use the return statement with the try. catch. finally statement, the finally block still executes after the return statement.
The result will be returned after the finally block is executed. Also, if the finally block has a return statement, the value from the finally block will be returned.
The try…finally statement
In the try. catch..finally statement, either the catch or finally block is optional. Therefore, you can have the try. finally statement like this:
try < // do something > finally < // clean up >
Code language: HTML, XML (xml)
The try. finally statement allows you to throw an exception while cleaning up the resource appropriately.
Summary
- Use the try. catch. finally statement to handle exceptions and clean up the resources.
- The finally block always executes after the try or catch block.
- If the try or catch has the return statement, the value will be returned only after the finally block executes.
Обработка исключений
В процессе работы программы могут возникать различные ошибки, которые могут прервать работу программы. Например, рассмотрим следующую ситуацию:
$a = 5; $b = 0; $result = $a / $b; echo $result; echo "Конец работы программы";
Программа выводит результат деления. Поскольку делитель равен 0, а на ноль делить нельзя, то при выполнении деления программа завершится, и в браузере мы увидим что-то типа следующего:
Fatal error: Uncaught DivisionByZeroError: Division by zero in D:\localhost\hello.php:11 Stack trace: #0 thrown in D:\localhost\hello.php on line 11
Браузер отобразит нам произошедшую ошибку, причем дальше после строки с делением программа даже не будет выполняться.
Кто-то может сказать, что ситуация искуственная, так как мы сами определили делитель равный нулю. Но данные могут передаваться извне. Кроме того, кроме деления на ноль есть различные ситуации, при которых могут происходить ошибки. Но PHP предоставляет ряд возможностей для обработки подобных ситуаций.
Для обработки исключений в PHP применяется конструкция try-catch :
try < // код, который может вызвать исключение >catch(Тип_исключения $ex) < // обработка исключения >
Эта конструкция в общем варианте состоит из двух блоков — try и catch . В блок try помещается код, который потенциально может вызвать исключение. А в блоке catch помещается обработка возникшего исключения. Причем каждого типа исключения мы можем определить свою логику обработки. Конкретный тип исключения, который мы хотим обработать, указывается в круглых скобках после оператора catch :
После названия типа указывается переменная этого типа (в данном случае $ex ), которая будет хранить информацию об исключении и которую мы можем использовать при обработке исключения.
Если в блоке try при выполнении кода возникает ошибка, то блок try прекращает выполнение и передает управление блоку catch , который обрабатывает ошибку. А после завершения выполнения кода в блоке catch программа продолжает выполнять инструкции, которые размещены после блока catch .
Если в блоке try при выполнении кода не возникает ошибок, то блок catch не выполняется, а после завершения блока try программа продолжает выполнять инструкции, которые размещены после блока catch .
Например, обработаем ошибку с делением на ноль:
try < // код, который может вызвать исключение $a = 5; $b = 0; $result = $a / $b; echo $result; >catch(DivisionByZeroError $ex) < // обработка исключения echo "Произошло исключение:
"; echo $ex . "
"; > echo "Конец работы программы";
В данном случае код деления на ноль, поскольку он может потенциально вызвать ошибку, помещен в блок try .
В блоке catch обрабатывается ошибка типа DivisionByZeroError , которая генерируется при делении на ноль. Вся обработка сводится к выводу информации на экран.
В итоге при выполнении программа выведет следующее:
Произошло исключение: DivisionByZeroError: Division by zero in D:\localhost\hello.php:14 Stack trace: #0 Конец работы программы
Как видно из вывода программы, она не завершается аварийно при делении на ноль, а продолжает работу.
Типы ошибок и исключений
В PHP для разных ситуаций есть множество типов, которые описывают ошибки. Все эти встроенные типы применяют интерфейс Throwable :
Все типы делятся на две группы: собственно ошибки (класс Error ) и собственно исключения (класс Exception ). А от классов Error и Exception наследуются классы ошибок и исключений, которые описывают конкретные ситуации. Например, от класса Error наследуется класс ArithmeticError , который описывает ошибки, возникающие при выполнении арифметических операций. А от класса ArithmeticError наследуется класс DivisionByZeroError , который представляют ошибку при делении на ноль.
Блок catch
Конструкция try..catch позволяет определить несколько блоков catch — для обработки различных типов ошибок и исключений:
try < $result = 5 / 0; echo $result; >catch(ParseError $p) < echo "Произошла ошибка парсинга"; >catch(DivisionByZeroError $d)
При возникновении ошибки будет для ее обработки будет выбираться тот блок catch , который соответствует вошникшей ошибки. Так, в данном случае при делении на ноль будет выполняться второй блок catch .
Если бы в блоке try возникла бы ошибка, которая бы не соответствовала типам из блоков catch (в данном случае — типам DivisionByZeroError и ParseError), то такая ошибка не была бы обработана, и соответственно программа бы аварийно завершила свое выполнение.
Блоки catch с более конкретными типами ошибок и исключений должны идти в начале, а более с более общими типа — в конце:
try < $result = 5 / 0; echo $result; >catch(DivisionByZeroError $ex) < echo "На ноль делить нельзя"; >catch(ArithmeticError $ex) < echo "Ошибка при выполнении арифметической операции"; >catch(Error $ex) < echo "Произошла ошибка"; >catch(Throwable $ex)
Класс DivisionByZeroError унаследован от ArithmeticError, который, в свою очередь, унаследован от Error, реализующего интерфейс Throwable. Поэтому класс DivisionByZeroError представляет более конкретный тип и представляемые им ошибки должны обрабатываться в первую очередь. А тип Throwable представляет наиболее общий тип, так как ему соответствуют все возможные ошибки и исключения, поэтому блоки catch с таким типом должны идти в конце.
В данном случае опять же в блоке try происходит ошибка деления на ноль. Но этой ошибке соответствуют все четыре блока catch . Для обработки PHP будет выбирать первый попавшийся, который соответствует типу ошибки. В данном случае это блок для обработки ошибки типа DivisionByZeroError.
Если нам надо обрабатывать в принципе все ошибки и исключения, то мы можем определить только обработку общего для всех них типа Throwable:
Начиная с версии PHP 8.0 в блоке catch можно просто указать тип обрабатываемого исключения, не определяя переменную:
Получение информации об ошибках и исключениях
Интерфейс Throwable предоставляет ряд методов, которые позволяют получить некоторую информацию о возникшем исключении:
- getMessage() : возвращает сообщение об ошибке
- getCode() : возвращает код исключения
- getFile() : возвращает название файла, в котором возникла ошибка
- getLine() : возвращает номер строки, в которой возникла ошибка
- getTrace() : возвращает трассировку стека
- getTraceAsString() : возвращает трассировку стека в виде строки
Применим некоторые из этих методов:
try < $result = 5 / 0; echo $result; >catch(DivisionByZeroError $ex) < echo "Сообщение об ошибке: " . $ex->getMessage() . "
"; echo "Файл: " . $ex->getFile() . "
"; echo "Номер строки: " . $ex->getLine() . "
"; >
Сообщение об ошибке: Division by zero Файл: D:\localhost\hello.php Номер строки: 11
Блок finally
Конструкция try..catch также может определять блок finally . Этот блок выполняется в конце — после блока try и catch вне зависимости, возникла или нет ошибка. Нередко блок finally используется для закрытия ресурсов, которые применяются в блоке try.
try < $result = 5 / 0; echo $result . "
"; > catch(Throwable $ex) < echo "Ошибка при выполнении программы
"; > finally < echo "Блок finally
"; > echo "Конец работы программы";
Ошибка при выполнении программы Блок finally Конец работы программы
Конструкция try..catch..finally может содержать либо все три блока, либо только два блока try и либо блок catch , либо блок finally .
Try Catch PHP или исключения в PHP
Представляем вашему вниманию руководство для новичков о том, как использовать блоки Try Catch PHP . В этой статье я покажу, как перехватывать исключения.
Давайте сразу взглянем на пример сгенерированного исключения ( и впоследствии перехваченного ):
> //Перехватываем (catch) исключение, если что-то идет не так. catch (Exception $ex) < //Выводим сообщение об исключении. echo $ex->getMessage(); >
В приведенном выше примере я продемонстрировал использование TRY и CATCH , в котором исключение всегда сгенерировано ( только ради примера ):
- Внутри блока TRY мы проверяем, равняется ли цифра 1 цифре 2 . Так как она не равняется ( и никогда не будет равняться ), мы генерируем исключение с сообщением “ 1 не равняется 2! ”;
- Внутри блока CATCH мы перехватываем исключение и выводим соответствующее сообщение.
- TRY : внутри блока PHP try мы задаем логику приложения. Этот блок содержит код, который может или не может сгенерировать исключение;
- CATCH : блок CATCH будет перехватывать любые исключения, проявившиеся в предыдущем блоке TRY . Код внутри блока CATCH будет исполнен только в случае обнаружения исключения;
- FINALLY : если вы используете PHP 5.5 и выше, то вы можете использовать блок FINALLY . Расположенный в нем код исполняется всегда, вне зависимости от того, было ли обнаружено исключение.
Когда используются исключения?
Исключения используются, когда результат операции отличается от того, что ожидало ваше приложение. К примеру, если ваше приложение пытается прочитать CSV-файл на сервере, а этого файла не существует, то можно сгенерировать исключение. Использование PHP try catch в примере:
> //Перехватываем (catch) исключение, если что-то идет не так. catch (Exception $ex) < //Выводим сообщение об исключении. echo $ex->getMessage(); >
В приведенном выше примере использования в PHP try exception мы генерируем исключение тогда, когда не можем открыть запрашиваемый файл. И генерируем мы его, так как файл должен был существовать. Примеры ситуаций, когда вы можете генерировать исключения:
- Ваше PHP-приложение не может подключиться к MySQL ;
- Ошибка при запросе к базе данных;
- Ошибка при запросе к API ;
- Получен некорректный тип запроса;
- Отсутствуют необходимые переменные $_POST или $_GET .
Нужно ли перехватывать все исключения?
Лично я так не считаю. К примеру: вам не удается подключиться к базе данных, и генерируется исключение, нужно ли тогда исполнять весь оставшийся код? Если весь последующий код привязан к базе данных, которой просто не существует, то зачем же его исполнять?
По моему мнению, исключения нужно перехватывать с помощью PHP try catch finally только, если это не оказывает негативного влияния на остальные функции приложения.
Например: если API-запрос к внешнему сервису выдает ошибку, то вы можете перехватить исключение и вывести дружественное пользователю сообщение « Невозможно подключиться к базе данных » или « Информация о погоде недоступна ».
Не перехваченные исключения следует обрабатывать с помощью пользовательского обработчика. Так вы сможете обрабатывать не перехваченные исключения, и выводить понятные человеку сообщения или заглушки.