16

I understand what the "finally" keyword is used for in various languages, however, I struggle to understand why you would use it outside of there being a formatting preference in taste.

For instance, in PHP:

try {
  possibleErrorThrownFunction();
}
catch (CustomException $customException) {
  // handle custom error
}
catch (Exception $exception) {
  // handle the error
}
finally {
  // run this code every single time regardless of error or not
}

What's the difference between what this code is doing and this?

try {
  possibleErrorThrownFunction();
}
catch (CustomException $customException) {
  // handle custom error
}
catch (Exception $exception) {
  // handle the error
}

// run this code every single time regardless of error or not

Doesn't that last line always get run anyway due to the error being caught? In which case, there is no case to really use finally unless you just want to maintain a code-style formatting?

An example of a case where a finally statement is necessary and distinct from just putting code after try/catch statements would be helpful if I am missing something here.

Kaii
  • 20,122
  • 3
  • 38
  • 60
Jake
  • 6,096
  • 1
  • 10
  • 13
  • 11
    Finally will **always** be executed, if exception was thrown or not. This is often used for clean-up tasks like unlocking files or what the compiler (PHP) does not do itself. – Markus Zeller Jul 29 '19 at 20:20
  • 3
    As @MarkusZeller states, it's commonly used for cleanup. Checkout the java docs for a good detail: https://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html – BReal14 Jul 29 '19 at 20:21
  • 1
    @MarkusZeller php is interpreted, not compiled. – bassxzero Jul 29 '19 at 20:23
  • 8
    If you throw an exception that isn't handled by any of the catch clauses or if you throw an exception from within any of the handlers, then the code following the catch clauses will never be executed, while a finally block will get executed before the exception is further propagated down the call stack – foobar Jul 29 '19 at 20:24
  • 2
    @bassxzero Yes, the (PHP) code is interpreted, but in the end it is compiled to bytecode. That does not change the **finally** behavior. – Markus Zeller Jul 29 '19 at 20:30
  • @foobar in the example there is an explicit `catch (\Exception $e)` which catches all.. so this does not make a difference here. – Kaii Jul 29 '19 at 20:42
  • 1
    @Kaii I just wanted to cover all cases where an exception might escape. For the op's specific example my 2nd statement still holds true, where throwing an exception from within one of the handlers will prevent execution of any code following it, unless it is placed within a finally block – foobar Jul 29 '19 at 20:49
  • `Finally` is there because sane people usually don't catch the base exception like that. And sometimes, even catch statement itself is not specified. In those cases, finally is the guaranteed way of executing the cleanup tasks. – Mat J Jul 30 '19 at 13:37

2 Answers2

30

Short Answer

Finally blocks are guaranteed to run no matter what happens inside of the try and catch blocks, before allowing the program to crash.

This is sort of explained here: https://www.php.net/manual/en/language.exceptions.php though the explanation isn't particularly detailed.

Some More Detail

One example that comes to the top of my head is if you are dealing with input/output streams or something similar that has to be closed after use in order to avoid a memory leak. To use your example:

try {
  memoryUser.startReading(someFileOrSomething);
}
catch (CustomException $customException) {
  // handle custom error
}
catch (Exception $exception) {
  // handle the error
  invisibleBug.whoops(); // i.e. something goes wrong in this block
}

memoryUser.Close(); // because something went wrong in the catch block,
                    // this never runs, which, in this case, causes a memory leak

In this case, wrapping the memoryUser.Close(); in a finally block would ensure that that line would run before the rest of the program exploded, preventing the memory leak even in an otherwise catastrophic failure.

TL;DR

So a lot of the time, people put the finally block there to ensure an important line runs, even if they overlooked something in the catch blocks. This is how I've always seen it used.

Hopefully this helps :)

Reagan Duggins
  • 394
  • 3
  • 6
  • 1
    Just to make sure I understand what you're conveying, the condition that I'm not seeing is when an error occurs in the catch statement(s); in which case a finally statement can still run despite a new, uncaught error arising? The implication being, that you _should_ in fact use finally statements since you can't always predict errors in catch statements? – Jake Jul 29 '19 at 21:26
  • 1
    Although the syntax appears to be Java, this is a good example and explanation. – Adam Rodriguez Jul 29 '19 at 21:58
  • 2
    Precisely :) Another possible exception for when you might not need a finally block could be if the catch is incredibly simple (like maybe `System.out.println("uh oh");` but it I usually just prefer being safe to sorry :) @adam thank you and good eye. I am more familiar with Java, but figured that the concept would be the same. – Reagan Duggins Jul 29 '19 at 22:34
  • "Finally blocks are guaranteed to run no matter what happens inside of the try and catch blocks". If PHP is like any other language (well that's a big if, but it generally isn't better than others) I seriously doubt that. Apart from the nitpicky endless loop scenarios, PHP does have an `exit` function, which I assume calls the C runtime's exit, which means the process is simply torn down and no finally block is executed. Same happens in .NET or Java. – Voo Jul 30 '19 at 10:21
  • 1
    @Jake - Sometimes you also DON'T write catch blocks. Like `try { ... } finally {... }`. Then the exception will get propagated upwards (caught in some other method which can handle it), but the `finally` block will run anyway cleaning up whatever needs to be cleaned up. – Vilx- Jul 30 '19 at 11:38
  • 1
    @Jake - And at other times, you don't _fully_ handle the exception. Like, you do a little bit in your `catch` (maybe log it or add some details to the exception object), but then re-throw the exception so that some higher level can catch it and handle it properly. Again, `finally` cleans up. – Vilx- Jul 30 '19 at 11:39
27

What's special about a finally {} block is that it will always run at the end of the try {} block.

  • It will run if the code in the try {} block completes successfully.

  • It will run if the code in the try {} block throws an exception that was caught by a catch {}. (The finally {} runs after the catch {}.)

  • It will run if the code in the try {} block throws an exception that wasn't handled by any catch {} block, or if there weren't any at all. (The finally {} block runs before the exception is propagated to the caller.)

  • It will run if the code in the try {} block throws an exception, and the code in the catch {} throws another exception (or rethrows the same exception).

  • It will even run if the code in the try {} block, or in a catch {} block, uses return. (Just as with an uncaught exception, the finally {} runs before the function actually returns.) The finally {} block can even use return itself, and its return value will override the value that the other block tried to return!

(There is one edge case where a finally {} block won't run, and that's if the entire process is destroyed, e.g. by being killed, or by calling exit() or die().)

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • To compare and contrast the two snippets in the question, it might be worth mentioning in which of these cases regular code after the `try/catch/finally` would run. (The first two? I'm not sure.) – ilkkachu Jul 30 '19 at 12:36
  • @ilkkachu yes only in the first two. – Kaii Jul 30 '19 at 14:12