| 
        php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login | 
  [2005-02-25 07:07 UTC] ceefour at gauldong dot net
 Description:
------------
PHP 5 has specifically decided not to support 'finally'. Why?
This is one of numerous cases why finally is useful:
mysql_query("LOCK TABLES mytable WRITE");
try {
  // ... do lots of queries here
} finally {
  mysql_query("UNLOCK TABLES");
}
You need to use UNLOCK TABLES otherwise your tables won't get unlocked when an exception is thrown. This is especially bad if you use persistent connections.
It is possible to emulate finally using try/catch but this introduces code redundancy and may create inconsistent code:
mysql_query("LOCK TABLES mytable WRITE");
try {
  // ... do lots of queries here
  mysql_query("UNLOCK TABLES");
} catch(Exception $e) {
  mysql_query("UNLOCK TABLES");
  throw $e;
}
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits             
             | 
    |||||||||||||||||||||||||||||||||||||
            
                 
                Copyright © 2001-2025 The PHP GroupAll rights reserved.  | 
        Last updated: Tue Nov 04 01:00:02 2025 UTC | 
We've had long discussions and came to the only conclusion that we don't need that, for more search the mailing list archieves. Besides the following is absolutley equivalent: mysql_query("LOCK TABLES mytable WRITE"); try { // ... do lots of queries here } catch (Exception $e) { // do nothing here } mysql_query("UNLOCK TABLES"); The only difference is the second example does rethrow the exception. Though this is still possible (however much more to type) it is wrong design. Since obviously you are using the exceptions as control flow. And that design looks like Java where it unlike with PHP makes somewhat sense.Could finally also mean that 'returns' will be executed after the finally block try{ some ifs ... return x ... more ifs ... throw ... return y }catch{ handle exceptions }finally{ No matter if there was exception or not execute this bit before you leave the method. For example if object has some state it might be necessary to make sure its consistent at the end } In the case i have now at work i had to add method call before every return and throw to make sure that my data will be set properly before method ends. Would that be a feature someone might like? thanks art>We've had long discussions and came to the only conclusion that we don't need that, for more search the mailing list archieves. Where is that discussion? I haven't been able to find it. Only people saying that finally is utterly useless, without showing any signs that they have actually considered finally's uses. As the other comments have said, sometimes some code inside a try will allocate a non-php ressource which need to be deallocated whether or not an exception is thrown. To avoid writing that code twice, you need it in finally. Version without finally: try { allocate non-php resource } catch ($ex) { deallocate non-php resource throw $ex; } deallocate non-php resource Version with finally: try { allocate non-php resource } finally { deallocate non-php resource } The finally code is obviously "better". And it is a completely reasonable way to code. Sure you can emulate finally with more code, but so can a Turin Machine. finally is syntactic sugar which makes it easier to write maintainable programs.I also think that try-finally is useful. try catch is no elegant replacement. Just needed it today again. finally is more elegant than an other solution. For example: try { lots o' code if a return .. if b exit .. } finally do somethin } Another solution to the "finally" problem is to use goto. Not so elegant but not a bad thing according to Knuth.I noticed this bug because I have exactly the same problem atm and finally could solve it. I found a great discussion about the "return" problem and how it's solved in java. (IMHO I think that's the right way) stackoverflow dot com/questions/65035/in-java-does-return-trump-finally In PHP it could be implemented like the following: function example1() { try { return "Return\n"; } finally { echo "Finally\n"; } } echo example1(); Output: Finally Return And it's important that finally has the right to overwrite return. (Although I think that there only a few cases where that would be useful) function example2() { try { return "Return wins\n"; } finally { return "Finally wins\n"; } } echo example2(); Output: Finally wins I hope that helps a bit more why finally would be a very useful in php! Thanks.> c891652 at bofthew dot com I'm disappointed about this request is closed without critical reasons. The first comment author doesn't understand OOP correctly. The code cannot raise exception to upper class. The code would be following without finally statement. // create temporary file try{ // write to temporary file }catch(ConnectionException $e){ // delete temporary file } // delete temporary file The "delete temporary file" sentence would be duplicate. I can write with finally as following without duplicate "delete temporary file". // create temporary file try{ // write to temporary file }finally{ // delete temporary file }"finally" is very useful for using ADODB: $db->StartTransaction(); try{ .... ... any exception can occur here... .... } finally { $db->CompleteTrans(); } Even there is exception occur in try block, the CompleteTrans() always be called.--- Disable user permission checking try { Call a half a dozen methods } finally { Re-enable user permission checking } --- The ten year old discussion I found on the issue (http://marc.info/?l=php-internals&m=96774165717219&w=3) doesn't seem terribly applicable to my case. Specifically, it suggests: --- try { ... modify contents ... } catch { ... any error recovery code here ... } ... cleanup code ... --- Except my code doesn't 'recover' from errors. It runs back up the call stack and reports the error to the user. I have absolutely zero use for a catch here. My workaround (which, unlike a basic rethrow preserves the line/file): --- Disable permission checking try { Run methods } catch (Exception $e) { Enable permission checking throw new Exception($e->getMessage(), $e->getCode(), $e); } Enable permission checking --- The workaround simply requires a few extra lines of code and a bunch of duplicated code. But hey, finally isn't required, so it's all good.PHP++ for finally in PHP ;) my code: disableSIPTrunk (10 lines of code) try { // do some stuff } finally { enableSIPTrunk (10 lines of code) } // saves duplicate code and it's very elegant !Ugly workaround hack time! (This is not a substitute for a real language feature!) Mix and match with try/catch blocks as necessary. <?php // Usage examples // With no lambda functions <5.3, we do this instead :( function example_finally() { print "Finally was called!\n"; } function example1() { $finally = new Finally("example_finally"); print "Not throwing exception.\n"; $finally->invoke(); print "Example 1 ended normally.\n"; } function example2() { $finally = new Finally("example_finally"); print "Throwing exception!\n"; throw new Exception("Something exceptional happened!"); $finally->invoke(); print "Example 2 ended normally.\n"; } // Test harness print "Example 1...\n"; try { example1(); } catch (Exception $e) { print "Example 1 threw an exception!\n"; } print "\nExample 2...\n"; try { example2(); } catch (Exception $e) { print "Example 2 threw an exception!\n"; } // Implementation of the Finally class class Finally { private $_callback = NULL; private $_args = array(); function __construct($callback, array $args = array()) { if (!is_callable($callback)) { throw new Exception("Callback was not callable!"); } $this->_callback = $callback; $this->_args = $args; } public function invoke() { if ($this->_callback) { call_user_func_array($this->_callback, $args); $this->_callback = NULL; $this->_args = array(); } } function __destruct() { $this->invoke(); } }My two cents... Here's an example of emulating "finally" in PHP without needing to duplicate code. $_ex = null; AllocateSomeResource(); try { DoSomeProcessing(); } catch (Exception $ex) { $_ex = $ex; } DeallocateSomeResource(); if ($_ex != null) { throw $_ex; } That said, I completely agree any current workaround/emulation/"solution" is nothing but cumbersome and bug-prone, and that we shouldn't have to come up with such creative ways to overcome what seems like a language design flaw. PHP is a tool, it is supposed to work *with* us, not *against* us.RAII is an elegant solution for tidying up scopes reliably. It is also possible in PHP to do RAII without writing one class per resource type: <?php class ScopeGuard { private $callback; function __construct($callback) { $this->callback = $callback; } function __destruct() { if (is_callable($this->callback)) { call_user_func($this->callback); } } } function do_something() { mysql_query("LOCK TABLES mytable WRITE"); $guard = new ScopeGuard(function() { mysql_query("UNLOCK TABLES"); }); try { // ... do lots of queries here } } ?> $guard will be destructed when leaving the do_something - either by throwing an exception or by exiting the function normally. HOWEVER: RAII in C++ (which neither employs nor needs a finally keyword) is more subtle - or rather: Scopes are. In PHP you can define a variable within a loop or a conditional block - and use it afterwards. In C++ you can't. A variable defined inside a certain block will be destroyed once the block is left. Consider the following example: <?php function do_something() { if (foo) { mysql_query("LOCK TABLES mytable WRITE"); $guard = new ScopeGuard(function() { mysql_query("UNLOCK TABLES"); }); try { // ... do lots of queries here } // *1* } do_something_else(); // *2* } ?> In C++, this would work as expected of a "finally" replacement and unlock the tables at *1*, when the if scope closes. In PHP however, $guard will only be destroyed when leaving the function at *2*. This can be fixed by manually adding an unset($guard) at *1*, but this is inelegant and error prone. So, while I have never needed finally, I think the way PHP works and is used absolutely validates its introduction as a useful addition to the language. The alternative would be to introduce C/++ style closed scopes, but those would most likely not only break a lot of existing code, but the coders as well, as they do not even remotely fit into the way PHP is written.Finally is absolutely necessary for proper management of disposable resources. There is no easy to read workaround for try { causeException(); } finally { releaseResource(); } others pointed out that solving this issue kills re-throw, which is equally important.Most of the exceptions people come across in their PHP code tends to be for either File IO, or database access. Both of these need a finally to ensure the handle/connection/whatever gets closed, or dealt with in some other way. Using try/catch is already a lot more cumbersome then a world without Exceptions, but without finally, it adds a lot duplication and state management. For example in my own code I do something along the lines of ... -------------------------------------------------------- $time = microtime( true ); $sql = generateSQLQuery(); $conn = openDBConnection(); $ex = null; try { $result = runSQLQuery( $conn, $sql ); } catch ( Exception $ex ) { /* do nothing */ } closeDBConnection( $conn ); logSQLQuery( $sql, microtime(true) - $time ); if ( $ex !== null ) { throw $ex; } -------------------------------------------------------- ... which could just be ... -------------------------------------------------------- $time = microtime( true ); $sql = generateSQLQuery(); $conn = openDBConnection(); try { $result = runSQLQuery( $conn, $sql ); } finally { closeDBConnection( $conn ); logSQLQuery( $sql, microtime(true) - $time ); } -------------------------------------------------------- Simpler to write, easier to read, harder to get wrong, and more elegant. Please re-open this.This is awesome ! My next suggestion would be automatic resource management. e.g. in Scala : import resource._ val first_ten_bytes = managed(new FileInputStream("test.txt")) map { input => val buffer = new Array[Byte](10) input.read(buffer) buffer } or in Java 7 : static String readFirstLineFromFile(String path) throws IOException { try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); } } But "finally" as it stands already rocks!!! Hopefully we can see it in PHP sooner than later..... We've been waiting for a little bit too long (7 years) ;-)