Question

I don't have the required version of PHP that supports finally, so I am wondering if this:

try {
    work();
} catch (Exception $e) {
    cleanup();
    throw $e;
}

cleanup();

is exactly the same as

try {
    work();
} finally {
    cleanup();
}
Was it helpful?

Solution

The point of the finally block is to execute regardless of what happens in the try block, or in following catch cases. So if you think about it, the code in the finally block is executed either after a successful try block execution, or after any exception was thrown. So if you write it just as you did in your solution, then you do indeed mimic the situation exactly. If there is no exception, the code after the try/catch structure is executed; and if there is an exception—any exception—you also execute it.

I think the only situation which the finally support may rescue you from, which your version inherently can’t, is when you are actually aborting the outer execution stack early. For example if this code is inside a function and you are returning from within the try block, then the finally would still be executed, but in your manual implementation it of course couldn’t.

So if you make sure that you do not leave early, then yes, it should work in the same way.

There are not many ways to leave a function early that don’t throw an exception; return is the most obvious and aborting the program with exit, die or similar would be another.

OTHER TIPS

Finally code blocks execute always - if there's an exeption, and if there isn't. But if you catch an exeption and do cleanup() after catch block, then yes - it's basically the same thing.

From the PHP docs:

In PHP 5.5 and later, a finally block may also be specified after the catch blocks. Code within the finally block will always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.

If you look at the examples, you'll notice that the finally block will always execute even if the exception is caught. However, when there is an exception, the code will not resume, so the finally block is a good way to ensure that certain lines of code are always executed even if there is an exception.

The finally block will matter if your catch block uses a return function or something like that. Otherwise, there is no difference between putting your cleanup in the finally block or after your try/catch

Here's the example in question from the doc comments:

Just an example why finally blocks are usefull (5.5)

<?php

//without catch
function example() {
  try {
    //do something that throws an exeption
  }
  finally {
    //this code will be executed even when the exception is executed
  }
}

function example2() {
  try {
     //open sql connection check user as example
     if(condition) { 
        return false;
     }
  }
  finally {
    //close the sql connection, this will be executed even if the return is called.
  }
}

?>

Generally, yes.

Most of times, both examples work equivalently:

<?php
function work_success() {
    echo 'working' . PHP_EOL;
}

function work_fail() {
    echo 'working with fail' . PHP_EOL;
    throw new Exception('exception');
}

function cleanup() {
    echo 'cleanup' . PHP_EOL;
}

Code without finally:

try {
    work();
} catch (Exception $e) {
    cleanup();
    throw $e;
}
cleanup();

Code with finally:

try {
    work();
} finally {
    cleanup();
}

Results when work = work_success for both finally and non-finally versions:

working
cleanup

Results when work = work_fail for both finally and non-finally versions:

working
cleanup
Exception: exception

However, there are caveats.

Like @poke said, using your examples together with control flow mechanisms might get funny results. Here's an illustration of this using simple return statement:

function test()
{
    try {
        return 'success';
    } catch (Exception $e) {
        cleanup();
        throw $e;
    }
    cleanup();
}

echo test();

This will output just success. cleanup() won't get fired unless an exception is thrown. According to prior examples, equivalent finally counterpart to above example would look like this:

function test()
{
    try {
        return 'success';
    } finally {
        cleanup();
    }
}

echo test();

Note that this will execute cleanup() regardless of any exceptions, so the output will be:

cleanup
success

For some people it's suprising that code in finally block is executed prior to return statements. As long as you are aware of this, there should be no problems.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top