PHP prior to version 5.5 has no finally block - i.e., whereas in most sensible languages, you can do:
try {
//do something
} catch(Exception ex) {
//handle an error
} finally {
//clean up after yourself
}
PHP has no notion of a finally block.
Anyone have experience of solutions to this rather irritating hole in the language?
Solution, no. Irritating cumbersome workaround, yes:
Yucky, but should work.
Please note: PHP 5.5 finally (ahem, sorry) added a finally block: https://wiki.php.net/rfc/finally (and it only took a few years... available in the 5.5 RC almost four years to the date since I posted this answer...)
As this is a language construct, you won't find an easy solution for this. You can write a function and call it as the last line of your try block and last line before rethrowing the excepion in the try block.
Good books argues against using finally blocks for any other than freeing resource as you can not be sure it will execute if something nasty happens. Calling it an irritating hole is quite an overstatement. Believe me, a hell lot of exceptionally good code is written in languages without finally block. :)
The point of finally is to execute no matter if the try block was successfull or not.
Here is my solution to the lack of finally block. It not only provides a work around for the finally block, it also extends the try/catch to catch PHP errors (and fatal errors too). My solution looks like this (PHP 5.3):
You can download the solution with documentation and examples from git hub - https://github.com/Perennials/travelsdk-core-php/tree/master/src/sys
I just finished writing a more elegant Try Catch Finally class which may be of use to you. There are some drawbacks but they can be worked around.
https://gist.github.com/Zeronights/5518445
The RAII idiom offers a code-level stand-in for a
finally
block. Create a class that holds callable(s). In the destuctor, call the callable(s).Coordination
Note that PHP doesn't have block scope for variables, so
Finally
won't kick in until the function exits or (in global scope) the shutdown sequence. For example, the following:will result in the output:
$this
PHP 5.3 closures can't access
$this
(fixed in 5.4), so you'll need an extra variable to access instance members within some finally-blocks.Private and Protected Fields
Arguably the biggest problem with this approach in PHP 5.3 is the finally-closure can't access private and protected fields of an object. Like accessing
$this
, this issue is resolved in PHP 5.4. For now, private and protected properties can be accessed using references, as Artefacto shows in his answer to a question on this very topic elsewhere on this site.Private and protected methods can be accessed using reflection. You can actually use the same technique to access non-public properties, but references are simpler and more lightweight. In a comment on the PHP manual page for anonymous functions, Martin Partel gives an example of a
FullAccessWrapper
class that opens up non-public fields to public access. I won't reproduce it here (see the two previous links for that), but here is how you'd use it:try/finally
try
blocks require at least onecatch
. If you only wanttry/finally
, add acatch
block that catches a non-Exception
(PHP code can't throw anything not derived fromException
) or re-throw the caught exception. In the former case, I suggest catchingStdClass
as an idiom meaning "don't catch anything". In methods, catching the current class could also be used to mean "don't catch anything", but usingStdClass
is simpler and easier to find when searching files.Call using closures. Second parameter,
$catch
, is optional. Examples:Properly handles exceptions everywhere:
$try
: Exception will be passed to$catch
.$catch
will run first, then$finally
. If there is no$catch
, exception will be rethrown after running$finally
.$catch
:$finally
will execute immediately. Exception will be rethrown after$finally
completes.$finally
: Exception will break down the call stack unimpeded. Any other exceptions scheduled for rethrow will be discarded.$try
will be returned.