You get a bonus - 1 coin for daily activity. Now you have 1 coin

The Finally block - Try-catch exception handling: what's the difference

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 exception
die();
} 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.

The Finally block

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!

Exceptions

The general concept of an exceptional situation

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.

  • Integer division by zero. This operation cannot have a finite result, so neither further computation nor an attempt to use the result of the division will lead to a solution of the task.
  • An error while attempting to read data from an external device. If the data cannot be obtained, any further planned operations on it are pointless.
  • Exhaustion of available memory. If at some point the system is unable to allocate enough RAM for the application program, the program will not be able to work normally.
  • The appearance of an emergency power-off signal for the system. The application task will most likely not be solved; at best (if there is some power reserve) the application program can take care of saving the data.

Types of exceptional situations

Exceptional situations that arise while a program is running can be divided into two main types: synchronous and asynchronous, whose response principles differ significantly.

  • Synchronous exceptions can only occur at certain, predetermined points in the program. For example, a file or communication channel read error, or lack of memory, are typical synchronous exceptions, since they only arise during a read operation or a memory allocation operation respectively.
  • Asynchronous exceptions can occur at any moment in time and don't depend on which specific instruction of the program the system is executing. Typical examples of such exceptions are an emergency power failure or the arrival of new data.

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.

Exception handlers

General description

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.

  • Handling with return means that the exception handler eliminates the problem that arose and brings the program to a state where it can continue running according to the main algorithm. In this case, once the handler code has executed, control is passed back to the point in the program where the exceptional situation arose (either to the instruction that caused the exception, or to the one following it, as in some old dialects of BASIC), and program execution continues. Handling with return is typical for handlers of asynchronous exceptions (which usually arise for reasons not directly related to the code being executed); it is of little use for handling synchronous exceptions.
  • Handling without return consists of the fact that after the exception handler code executes, control is passed to some predetermined place in the program, and execution continues from there. That is, in effect, when an exception occurs, the instruction during whose execution it arose is replaced with an unconditional jump to the specified statement.

There are two ways of attaching an exceptional-situation handler to a program: structured and unstructured exception handling.

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.

Structured exception handling

продолжение следует...

Продолжение:


Часть 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

See also

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Running server side scripts using PHP as an example (LAMP)"

Terms: Running server side scripts using PHP as an example (LAMP)