Lecture
Это продолжение увлекательной статьи про try-catch.
...
!important; float: none !important; height: auto !important; font-variant-numeric: normal !important; font-variant-east-asian: normal !important; font-stretch: normal !important; line-height: normal !important; margin: 0px !important; outline: 0px !important; overflow: visible !important; padding: 0px 1em !important; position: static !important; vertical-align: baseline !important; width: auto !important; min-height: auto !important; white-space: pre !important;">try {
// init bootstrapping phase$config_file_path = "config.php";if (!file_exists($config_file_path)){throw new ConfigFileNotFoundException("Configuration file not found.");}// continue execution of the bootstrapping phase} catch (ConfigFileNotFoundException $e) {echo "ConfigFileNotFoundException: ".$e->getMessage();// other additional actions that you want to carry out for this exceptiondie();} catch (Exception $e) {echo $e->getMessage();die();}?>First, we defined the ConfigFileNotFoundException class, which extends the base Exception class. It now becomes our custom exception class, and we can use it whenever we want to throw a ConfigFileNotFoundException exception in our application.
Then we used the throw keyword to throw a ConfigFileNotFoundException exception in case the config.php file doesn't exist. However, the important difference is in the catch block. As you can see, we defined two catch blocks, and each block is used to catch a different type of exception.
The first one catches exceptions of type ConfigFileNotFoundException. So if the exception being thrown is of type ConfigFileNotFoundException, this block will be executed. If the exception type doesn't match any particular catch block, it will match the last one, which should catch all generic exception messages.
In this section we'll look at how you can use the finally keyword together with the try and catch blocks. Sometimes you want to execute a piece of code regardless of whether an exception was thrown. That's where you can use a finally block, since the code you place in the finally block will always run after the try and catch blocks execute, regardless of whether an exception was thrown.
Let's try to understand this using the following example.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
|
try {// code// if something is not as expected// throw exception using the "throw" keyword// code, it won't be executed if the above exception is thrown} catch (Exception $e) {// exception is raised and it'll be handled here// $e->getMessage() contains the error message} finally {// code, it'll always be executed} |
The code in the example above is almost the same, with the only difference being that we added a finally block after the catch block. And, as we discussed, the code in this block will always execute.
The typical use cases we could come up with for the finally block are usually related to resource cleanup. For example, if you opened a database connection or a file on disk in the try block, you can perform cleanup tasks, such as closing the connection, in the finally block, since it's guaranteed to run.
Exception handling is a key coding skill, and you should think about how exceptions will be handled when developing your applications. This will help you detect and recover from unexpected errors in your application. I hope this post inspires you to write better error-handling code!
During program execution, situations can arise where the state of external data, I/O devices, or the computer system as a whole makes further computation according to the underlying algorithm impossible or meaningless. Classic examples of such situations are given below.
Exceptional situations that arise while a program is running can be divided into two main types: synchronous and asynchronous, whose response principles differ significantly.
Some types of exceptions can be classified as either synchronous or asynchronous. For example, a divide-by-zero instruction should formally result in a synchronous exception, since logically it arises precisely when that instruction executes, but on some platforms, due to deep pipelining, the exception may in fact turn out to be asynchronous.
In the absence of its own exception-handling mechanism for application programs, the most general response to any exceptional situation is to immediately halt execution and display a message to the user about the nature of the exception. It can be said that in such cases the operating system becomes the sole, universal exception handler. For example, the Windows operating system has a built-in Dr. Watson utility, which collects information about an unhandled exception and sends it to a special Microsoft server.
It's possible to ignore the exceptional situation and continue working, but such a tactic is dangerous, since it leads to incorrect program results or to errors arising later on. For example, if a program ignores an error reading a block of data from a file, it will end up with data other than what it was supposed to read. The results of using that data cannot be predicted.
Handling exceptional situations within the program itself consists of the fact that, when an exceptional situation arises, control is transferred to some predefined handler — a block of code, a procedure, or a function that performs the necessary actions.
There are two fundamentally different mechanisms by which exception handlers operate.
There are two ways of attaching an exceptional-situation handler to a program: structured and unstructured exception handling.
Unstructured exception handling is implemented as a mechanism for registering handler functions or commands for each possible type of exception. The programming language or its system libraries provide the programmer with at least two standard procedures: registering a handler and unregistering a handler. Calling the first one «binds» a handler to a specific exception, while calling the second cancels that «binding». If an exception occurs, execution of the program's main code is immediately interrupted and the handler starts executing. When the handler finishes, control is transferred either to some predetermined point in the program or back to the point where the exception arose (depending on the handling method specified — with or without return). Regardless of which part of the program is currently executing, the last handler registered for a given exception always responds to it. In some languages a registered handler remains in effect only within the current block of code (procedure, function), in which case an unregistering procedure is not required. Below is a conditional fragment of program code with unstructured exception handling:
SetHandler(DBError, GoTo DBErr)
// A handler has been set for the "DBError" exception - the "GoTo DBErr" command
... // The statements that work with the DB are here
GoTo ClearDBErr // Unconditional jump command - bypasses the exception handler
DBErr: // label - control will jump here in the event of a DB error, via the handler that was set
... // DB exception handler
ClearDBErr:
// label - control will jump here if the controlled code executes without a DB error.
RemoveHandler(DBError)
// Handler removed
Unstructured handling is practically the only option for handling asynchronous exceptions, but for synchronous exceptions it is inconvenient: you have to call handler set/remove commands frequently, and there's always a risk of breaking the program's logic by missing a handler registration or unregistration.
продолжение следует...
Часть 1 Try-catch exception handling: what's the difference between exceptions and errors?
Часть 2 How to create custom exceptions - Try-catch exception handling: what's
Часть 3 The Finally block - Try-catch exception handling: what's the difference
Часть 4 The difference between bugs, exceptions, and end-user errors - Try-catch
Comments