[php-src] master: Deprecate returning from a finally block. (#22509)
Osama Aldemeery via GitHub <[email protected]>
| Newsgroups | gmane.comp.php.cvs.general |
|---|---|
| Message-ID | <[email protected]> |
Author: Osama Aldemeery (aldemeery)
Committer: GitHub (web-flow)
Pusher: Girgias
Date: 2026-08-18T20:09:21+01:00
Commit: https://github.com/php/php-src/commit/e721b3fdc35dc74121ed27ed43c2f9568f321bee
Raw diff: https://github.com/php/php-src/commit/e721b3fdc35dc74121ed27ed43c2f9568f321bee.diff
Deprecate returning from a finally block. (#22509)
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#deprecate_returning_from_a_finally_block
Changed paths:
A Zend/tests/try/finally_return_deprecation.phpt
M Zend/tests/exit_finally_3.phpt
M Zend/tests/gc/gc_050.phpt
M Zend/tests/generators/finally/return_return.phpt
M Zend/tests/generators/finally/yield_return.phpt
M Zend/tests/generators/get_return_and_finally.phpt
M Zend/tests/generators/gh11028_1.phpt
M Zend/tests/generators/gh11028_2.phpt
M Zend/tests/generators/gh11028_3.phpt
M Zend/tests/generators/yield_in_finally_cleanup.phpt
M Zend/tests/oss_fuzz_438780145.phpt
M Zend/tests/return_types/029.phpt
M Zend/tests/return_types/never_finally_return.phpt
M Zend/tests/try/bug70228.phpt
M Zend/tests/try/bug70228_2.phpt
M Zend/tests/try/bug70228_3.phpt
M Zend/tests/try/bug70228_4.phpt
M Zend/tests/try/bug70228_6.phpt
M Zend/tests/try/catch_finally_003.phpt
M Zend/tests/try/catch_finally_005.phpt
M Zend/tests/try/catch_finally_006.phpt
M Zend/tests/try/finally_goto_005.phpt
M Zend/tests/try/try_catch_finally_003.phpt
M Zend/tests/try/try_finally_013.phpt
M Zend/tests/try/try_finally_014.phpt
M Zend/tests/try/try_finally_021.phpt
M Zend/tests/try/try_finally_023.phpt
M Zend/tests/try/try_finally_027.phpt
M Zend/zend_compile.c
M Zend/zend_compile.h
M sapi/phpdbg/tests/exceptions_001.phpt
M sapi/phpdbg/tests/exceptions_002.phpt
Diff:
diff --git a/Zend/tests/exit_finally_3.phpt b/Zend/tests/exit_finally_3.phpt
index 12d7747adea9..a2ae2429b28e 100644
--- a/Zend/tests/exit_finally_3.phpt
+++ b/Zend/tests/exit_finally_3.phpt
@@ -15,5 +15,6 @@ function test() {
var_dump(test());
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
Exit
diff --git a/Zend/tests/gc/gc_050.phpt b/Zend/tests/gc/gc_050.phpt
index 0bedc7220fd4..cf30776d9de9 100644
--- a/Zend/tests/gc/gc_050.phpt
+++ b/Zend/tests/gc/gc_050.phpt
@@ -36,5 +36,6 @@ for ($i = 0; $i < 100000; $i++) {
}
echo "OK\n";
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
OK
diff --git a/Zend/tests/generators/finally/return_return.phpt b/Zend/tests/generators/finally/return_return.phpt
index 194fc93de7c2..895adc37cce3 100644
--- a/Zend/tests/generators/finally/return_return.phpt
+++ b/Zend/tests/generators/finally/return_return.phpt
@@ -27,7 +27,8 @@ $gen = gen();
$gen->rewind(); // force run
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
before return
before return in inner finally
outer finally run
diff --git a/Zend/tests/generators/finally/yield_return.phpt b/Zend/tests/generators/finally/yield_return.phpt
index 6191f389e53e..dbfabea50889 100644
--- a/Zend/tests/generators/finally/yield_return.phpt
+++ b/Zend/tests/generators/finally/yield_return.phpt
@@ -15,5 +15,6 @@ foreach (foo(1, 5) as $x) {
echo $x, "\n";
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
1
diff --git a/Zend/tests/generators/get_return_and_finally.phpt b/Zend/tests/generators/get_return_and_finally.phpt
index 150e5b83c4db..8ced4d0008b5 100644
--- a/Zend/tests/generators/get_return_and_finally.phpt
+++ b/Zend/tests/generators/get_return_and_finally.phpt
@@ -41,7 +41,8 @@ try {
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
int(42)
gen2() throw
Cannot get return value of a generator that hasn't returned
diff --git a/Zend/tests/generators/gh11028_1.phpt b/Zend/tests/generators/gh11028_1.phpt
index e1e7aa5019e5..d1c07dc9de66 100644
--- a/Zend/tests/generators/gh11028_1.phpt
+++ b/Zend/tests/generators/gh11028_1.phpt
@@ -24,7 +24,8 @@ test("false", false);
test("true", true);
test("object", new stdClass);
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
yield null
Keys must be of type int|string during array unpacking
yield false
diff --git a/Zend/tests/generators/gh11028_2.phpt b/Zend/tests/generators/gh11028_2.phpt
index ddc9618e8ed8..bf364329849f 100644
--- a/Zend/tests/generators/gh11028_2.phpt
+++ b/Zend/tests/generators/gh11028_2.phpt
@@ -15,6 +15,8 @@ $c = (function () {
})()[0];
?>
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
Warning: Undefined variable $a in %s on line %d
Fatal error: Uncaught Error: Keys must be of type int|string during array unpacking in %s:%d
diff --git a/Zend/tests/generators/gh11028_3.phpt b/Zend/tests/generators/gh11028_3.phpt
index 7ea1aac6f6cf..c58e00dc09b1 100644
--- a/Zend/tests/generators/gh11028_3.phpt
+++ b/Zend/tests/generators/gh11028_3.phpt
@@ -17,5 +17,6 @@ try {
echo $e->getMessage(), "\n";
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
exception
diff --git a/Zend/tests/generators/yield_in_finally_cleanup.phpt b/Zend/tests/generators/yield_in_finally_cleanup.phpt
index 9a76261e0d5e..538c14bdb774 100644
--- a/Zend/tests/generators/yield_in_finally_cleanup.phpt
+++ b/Zend/tests/generators/yield_in_finally_cleanup.phpt
@@ -47,5 +47,6 @@ gen4()->rewind();
?>
===DONE===
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
===DONE===
diff --git a/Zend/tests/oss_fuzz_438780145.phpt b/Zend/tests/oss_fuzz_438780145.phpt
index 4c6936a69a01..11797fcce999 100644
--- a/Zend/tests/oss_fuzz_438780145.phpt
+++ b/Zend/tests/oss_fuzz_438780145.phpt
@@ -20,6 +20,8 @@ test();
?>
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
Fatal error: Uncaught TypeError: test(): Return value must be of type int, string returned in %s:%d
Stack trace:
#0 %s(%d): test()
diff --git a/Zend/tests/return_types/029.phpt b/Zend/tests/return_types/029.phpt
index c6fb4432158c..8711df828fff 100644
--- a/Zend/tests/return_types/029.phpt
+++ b/Zend/tests/return_types/029.phpt
@@ -14,6 +14,8 @@ function foo() : array {
foo();
?>
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
Fatal error: Uncaught Exception: xxxx in %s:%d
Stack trace:
#0 %s(%d): foo()
diff --git a/Zend/tests/return_types/never_finally_return.phpt b/Zend/tests/return_types/never_finally_return.phpt
index b03859710276..2a6af6923eef 100644
--- a/Zend/tests/return_types/never_finally_return.phpt
+++ b/Zend/tests/return_types/never_finally_return.phpt
@@ -14,4 +14,6 @@ function foo() : never {
// Note the lack of function call: function validated at compile-time
?>
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
Fatal error: A never-returning function must not return in %s on line %d
diff --git a/Zend/tests/try/bug70228.phpt b/Zend/tests/try/bug70228.phpt
index 8b812517a305..b69034da8a6c 100644
--- a/Zend/tests/try/bug70228.phpt
+++ b/Zend/tests/try/bug70228.phpt
@@ -10,5 +10,6 @@ function foo() {
var_dump(foo());
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
string(2) "bb"
diff --git a/Zend/tests/try/bug70228_2.phpt b/Zend/tests/try/bug70228_2.phpt
index c988e706ce47..bbb44bcd6a42 100644
--- a/Zend/tests/try/bug70228_2.phpt
+++ b/Zend/tests/try/bug70228_2.phpt
@@ -16,5 +16,6 @@ function test() {
var_dump(test());
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
int(42)
diff --git a/Zend/tests/try/bug70228_3.phpt b/Zend/tests/try/bug70228_3.phpt
index 55dbe4f8914a..80a0f379765b 100644
--- a/Zend/tests/try/bug70228_3.phpt
+++ b/Zend/tests/try/bug70228_3.phpt
@@ -26,6 +26,7 @@ try {
} while ($e);
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
2
1
diff --git a/Zend/tests/try/bug70228_4.phpt b/Zend/tests/try/bug70228_4.phpt
index f0ab3b0c2c11..7e0fd78707d7 100644
--- a/Zend/tests/try/bug70228_4.phpt
+++ b/Zend/tests/try/bug70228_4.phpt
@@ -28,5 +28,6 @@ try {
} while ($e);
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
1
diff --git a/Zend/tests/try/bug70228_6.phpt b/Zend/tests/try/bug70228_6.phpt
index fc68657f4c15..5bc3a70bdcfe 100644
--- a/Zend/tests/try/bug70228_6.phpt
+++ b/Zend/tests/try/bug70228_6.phpt
@@ -14,5 +14,6 @@ function test($x) {
var_dump(test([1]));
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
int(42)
diff --git a/Zend/tests/try/catch_finally_003.phpt b/Zend/tests/try/catch_finally_003.phpt
index 610d701872b1..3cfb4fd6c5a1 100644
--- a/Zend/tests/try/catch_finally_003.phpt
+++ b/Zend/tests/try/catch_finally_003.phpt
@@ -32,7 +32,10 @@ function &bar($a) {
var_dump(foo("para"));
var_dump(bar("para"));
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
+Deprecated: Returning from a finally block is deprecated in %s on line %d
string(3) "try"
string(7) "finally"
string(7) "finally"
diff --git a/Zend/tests/try/catch_finally_005.phpt b/Zend/tests/try/catch_finally_005.phpt
index 7671d05df582..bc4a72155bf6 100644
--- a/Zend/tests/try/catch_finally_005.phpt
+++ b/Zend/tests/try/catch_finally_005.phpt
@@ -17,5 +17,6 @@ function foo ($a) {
var_dump(foo("para"));
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
int(3)
diff --git a/Zend/tests/try/catch_finally_006.phpt b/Zend/tests/try/catch_finally_006.phpt
index 216219b6a5b3..463ce377f0a3 100644
--- a/Zend/tests/try/catch_finally_006.phpt
+++ b/Zend/tests/try/catch_finally_006.phpt
@@ -22,7 +22,8 @@ try {
var_dump($e->getMessage());
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
string(4) "para"
string(7) "finally"
string(6) "return"
diff --git a/Zend/tests/try/finally_goto_005.phpt b/Zend/tests/try/finally_goto_005.phpt
index ffb0e68be103..0cb38a502993 100644
--- a/Zend/tests/try/finally_goto_005.phpt
+++ b/Zend/tests/try/finally_goto_005.phpt
@@ -11,5 +11,6 @@ label: try {
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
success
diff --git a/Zend/tests/try/finally_return_deprecation.phpt b/Zend/tests/try/finally_return_deprecation.phpt
new file mode 100644
index 000000000000..86cc07e59481
--- /dev/null
+++ b/Zend/tests/try/finally_return_deprecation.phpt
@@ -0,0 +1,86 @@
+--TEST--
+Returning from a finally block is deprecated
+--FILE--
+<?php
+
+function withValue() {
+ try {
+ } finally {
+ return 1;
+ }
+}
+
+function withoutValue() {
+ try {
+ } finally {
+ return;
+ }
+}
+
+// Not deprecated: the return belongs to the try block, not the finally.
+function inTry() {
+ try {
+ return 1;
+ } finally {
+ }
+}
+
+// Not deprecated: the return belongs to a catch block.
+function inCatch() {
+ try {
+ throw new Exception();
+ } catch (Exception $e) {
+ return 1;
+ } finally {
+ }
+}
+
+// Not deprecated: the return belongs to a nested closure, not the finally.
+function nestedClosure() {
+ try {
+ } finally {
+ $f = function () {
+ return 1;
+ };
+ }
+}
+
+// Deprecated twice: both returns are lexically inside the outer finally, even
+// though one of them sits in a nested try block.
+function nestedTry() {
+ try {
+ } finally {
+ try {
+ return 1;
+ } finally {
+ return 2;
+ }
+ }
+}
+
+// Deprecated once: only the closure's own finally return is flagged. The outer
+// finally must not leak into the closure, so the closure's try return is left alone.
+function closureWithTry() {
+ try {
+ } finally {
+ $f = function () {
+ try {
+ return 1;
+ } finally {
+ return 2;
+ }
+ };
+ }
+}
+
+?>
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
+Deprecated: Returning from a finally block is deprecated in %s on line %d
+
+Deprecated: Returning from a finally block is deprecated in %s on line %d
diff --git a/Zend/tests/try/try_catch_finally_003.phpt b/Zend/tests/try/try_catch_finally_003.phpt
index 4d285eedb8da..3e37256837b0 100644
--- a/Zend/tests/try/try_catch_finally_003.phpt
+++ b/Zend/tests/try/try_catch_finally_003.phpt
@@ -32,5 +32,6 @@ function foo () {
var_dump(foo());
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
1234int(4)
diff --git a/Zend/tests/try/try_finally_013.phpt b/Zend/tests/try/try_finally_013.phpt
index 0e82dcbb4cf4..1f0e044a1285 100644
--- a/Zend/tests/try/try_finally_013.phpt
+++ b/Zend/tests/try/try_finally_013.phpt
@@ -18,6 +18,7 @@ function foo() {
foo();
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
try
finally
diff --git a/Zend/tests/try/try_finally_014.phpt b/Zend/tests/try/try_finally_014.phpt
index a45f63f1f3d4..0cdc8ddffc8a 100644
--- a/Zend/tests/try/try_finally_014.phpt
+++ b/Zend/tests/try/try_finally_014.phpt
@@ -20,6 +20,7 @@ function foo() {
foo();
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
try
finally
diff --git a/Zend/tests/try/try_finally_021.phpt b/Zend/tests/try/try_finally_021.phpt
index d25f393be1f0..f624eeb5c6fb 100644
--- a/Zend/tests/try/try_finally_021.phpt
+++ b/Zend/tests/try/try_finally_021.phpt
@@ -15,6 +15,7 @@ foreach ([0] as $_) {
}
}
?>
---EXPECT--
+--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
ok
ok
diff --git a/Zend/tests/try/try_finally_023.phpt b/Zend/tests/try/try_finally_023.phpt
index e88eddb3b236..305684e3111b 100644
--- a/Zend/tests/try/try_finally_023.phpt
+++ b/Zend/tests/try/try_finally_023.phpt
@@ -31,6 +31,7 @@ try {
?>
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
Exception: 1 in %s:%d
Stack trace:
#0 %s(%d): test()
diff --git a/Zend/tests/try/try_finally_027.phpt b/Zend/tests/try/try_finally_027.phpt
index 1e66479eb09b..059a16a977f1 100644
--- a/Zend/tests/try/try_finally_027.phpt
+++ b/Zend/tests/try/try_finally_027.phpt
@@ -23,6 +23,7 @@ try {
?>
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
Exception: 1 in %s:%d
Stack trace:
#0 %s(%d): test()
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index c7ac93f8d34e..f3527330a2c9 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -348,6 +348,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_arra
CG(context).brk_cont_array = NULL;
CG(context).labels = NULL;
CG(context).in_jmp_frameless_branch = false;
+ CG(context).in_finally = false;
CG(context).active_property_info_name = NULL;
CG(context).active_property_hook_kind = (zend_property_hook_kind)-1;
}
@@ -6164,6 +6165,10 @@ static void zend_compile_return(const zend_ast *ast) /* {{{ */
}
}
+ if (CG(context).in_finally) {
+ zend_error(E_DEPRECATED, "Returning from a finally block is deprecated");
+ }
+
if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)
&& (expr_node.op_type == IS_CV || (by_ref && expr_node.op_type == IS_VAR))
&& zend_has_finally()) {
@@ -7410,7 +7415,10 @@ static void zend_compile_try(const zend_ast *ast) /* {{{ */
zend_emit_op(NULL, ZEND_JMP, NULL, NULL);
+ bool orig_in_finally = CG(context).in_finally;
+ CG(context).in_finally = true;
zend_compile_stmt(finally_ast);
+ CG(context).in_finally = orig_in_finally;
CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = opnum_jmp + 1;
CG(active_op_array)->try_catch_array[try_catch_offset].finally_end
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 3d4e6f3c3f9f..34a91183b2a9 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -207,6 +207,7 @@ typedef struct _zend_oparray_context {
zend_string *active_property_info_name;
zend_property_hook_kind active_property_hook_kind;
bool in_jmp_frameless_branch;
+ bool in_finally;
bool has_assigned_to_http_response_header;
} zend_oparray_context;
diff --git a/sapi/phpdbg/tests/exceptions_001.phpt b/sapi/phpdbg/tests/exceptions_001.phpt
index 2ebdc0f664d1..799832ae6d07 100644
--- a/sapi/phpdbg/tests/exceptions_001.phpt
+++ b/sapi/phpdbg/tests/exceptions_001.phpt
@@ -7,6 +7,7 @@ ev 1 + 2
c
q
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
[Successful compilation of %s]
prompt> handle first
[Uncaught Error in %s on line 16: Call to undefined function foo()]
@@ -22,6 +23,8 @@ Stack trace:
#0 %s(22): {closure:%s:%d}()
#1 {main}
[Script ended normally]
+
+Deprecated: Returning from a finally block is deprecated in %s on line %d
prompt>
--FILE--
<?php
diff --git a/sapi/phpdbg/tests/exceptions_002.phpt b/sapi/phpdbg/tests/exceptions_002.phpt
index 47d4c7d11c7d..a2c3e9298452 100644
--- a/sapi/phpdbg/tests/exceptions_002.phpt
+++ b/sapi/phpdbg/tests/exceptions_002.phpt
@@ -7,6 +7,7 @@ c
q
--EXPECTF--
+Deprecated: Returning from a finally block is deprecated in %s on line %d
[Successful compilation of %s]
prompt> handle first
[Uncaught Error in %s on line 16: Call to undefined function foo()]
@@ -26,6 +27,8 @@ Stack trace:
#0 %s(20): {closure:%s:%d}()
#1 {main}
[Script ended normally]
+
+Deprecated: Returning from a finally block is deprecated in %s on line %d
prompt> [The stack contains nothing !]
prompt>
--FILE--