|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2017-05-10 16:44 UTC] trianman at gmail dot com
Description: ------------ Return in a finally clause silently ignores an exception thrown in a try clause. I understand that there is no way to handle an exception here, but it MUST NOT be silently dropped out. The interpreter should trigger an E_NOTICE or something similar here. Looks like any version of PHP from 5.6 to 7.1.4 behaves in the same manner: https://3v4l.org/C16rP Here is a similar issue: https://bugs.php.net/bug.php?id=68270 Test script: --------------- <?php class MyException extends Exception { public function __construct($message = "", $code = 0, Throwable $previous = null) { print "2. Exception constructor\n"; parent::__construct($message, $code, $previous); } } function ololo() { try { print "1. Start\n"; throw new MyException("4. Exception message\n"); } finally { return "3. Return statement\n"; } } try { print ololo(); } catch (Exception $e) { print $e->getMessage(); } Expected result: ---------------- 1. Start 2. Exception constructor PHP NOTICE: Dropped exception due the return statement in a finally block 3. Return statement Actual result: -------------- 1. Start 2. Exception constructor 3. Return statement PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Nov 01 02:00:01 2025 UTC |
The correct way of writing this would be to catch the exception and throw it again, however this also fails. If it is not thrown again, then the behavior is correct. <?php class MyException extends Exception { public function __construct($message = "", $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); print "2. Exception constructed\n"; } } function throw_exception() { try { throw new MyException("5. Exception message\n"); } catch(Exception $exception) { print "3. Exception caught and thrown again\n"; throw $exception; } finally { return "4. Return statement\n"; } } try { print "1. Start\n"; print throw_exception(); } catch (Exception $e) { print $e->getMessage(); } The flow should be: exception is thrown, caught by the inner block, thrown again, caught by the outer block and then the finally block should execute, returning the flow to print throw_exception();This behaviour is also that used in Javascript. function foo() { try { throw 42; } finally { return "edge cases are hard"; } }; alert(foo());2 danack@php.net Sorry, I don't want to be mean. My English skills are not very good and it is sometimes hard to express my thoughts in a clear way. I've just realized that the finally statement is some-kind of antipattern for me. Because finally is a shortcut for catching and re-throwing an \Exception class eg. <?php try { throw new CustomException(); } catch (CustomException $ex) { handleException(); } catch (\Exception $ex) { doThingsInFinally(); throw $ex; } doThingsInFinally(); ?> Or with finally: <?php try { throw new CustomException(); } catch (CustomException $ex) { handleException(); } finally { doThingsInFinally(); } ?> Of cause if we have a return statement instead of a doTihingsInFinally() method, we will lose an exception. But we doing it in a clear way. On the other hand finally statement hides out from developer's eyes what actually is going. So for my mind a little copy-paste is a lesser evil than an unclear behavior. For all other guys the E_NOTICE will be enough. (:This faulty behaviour of the return statement in the finally{} of the the try{} block extends beyond the catchable error/exceptions. 1%0; // No warning or error. unknown_function(); // not reported. Program not aborted It took me days to locate a misspelled function, because no error is reported at all and program would normally abort, now continue with undesirable behaviour. Example code: <?php error_reporting(E_ALL|E_STRICT); function do_test(): int { try { 1/0; // a warning in php 7 - reported as documented nonexistent_function(); // a fatal error - not reported - program continues 1%0; // a fatal error return 0; } catch (Exception $e) { printf("CATCH\n"); return 1; } finally { printf("FINALLY\n"); return 2; } return 3; } printf("%d\n", do_test());