com php-src: Run finally if generator is closed before finishing: Zend/tests/generators/finally_ran_on_close.phpt Zend/ zend_generators.c
Zend/zend_generators.h
| From: | Gustavo André dos Santos Lopes | Date: | Fri, 24 Aug 2012 17:10:09 +0000 |
| Subject: | com php-src: Run finally if generator is closed before finishing: Zend/tests/generators/finally_ran_on_close.phpt Zend/ zend_generators.c Zend/zend_generators.h |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-70023@lists.php.net to get a copy of this message | ||
Commit: 4d8edda341efef1901365f10213c027e745ac7ab
Author: Nikita Popov <nikic@php.net> Fri, 24 Aug 2012 15:50:53 +0200
Parents: 7cdf6367a51a54fce8676aeb6fd32bf91b00f84b
Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=4d8edda341efef1901365f10213c027e745ac7ab
Log:
Run finally if generator is closed before finishing
Changed paths:
A Zend/tests/generators/finally_ran_on_close.phpt
M Zend/zend_generators.c
M Zend/zend_generators.h
Diff:
diff --git a/Zend/tests/generators/finally_ran_on_close.phpt
b/Zend/tests/generators/finally_ran_on_close.phpt
new file mode 100644
index 0000000..44a84fa
--- /dev/null
+++ b/Zend/tests/generators/finally_ran_on_close.phpt
@@ -0,0 +1,25 @@
+--TEST--
+finally is run even if a generator is closed mid-execution
+--FILE--
+<?php
+
+function gen() {
+ try {
+ echo "before yield\n";
+ yield;
+ echo "after yield\n";
+ } finally {
+ echo "finally run\n";
+ }
+
+ echo "code after finally\n";
+}
+
+$gen = gen();
+$gen->rewind();
+unset($gen);
+
+?>
+--EXPECT--
+before yield
+finally run
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index b4d8932..3170ec9 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -32,6 +32,39 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
if (generator->execute_data) {
zend_execute_data *execute_data = generator->execute_data;
+ if (!finished_execution) {
+ zend_op_array *op_array = execute_data->op_array;
+ if (op_array->has_finally_block) {
+ zend_uint op_num = execute_data->opline - op_array->opcodes;
+ zend_uint finally_op_num = 0;
+
+ /* Find next finally block */
+ int i;
+ for (i = 0; i < op_array->last_try_catch; i++) {
+ zend_try_catch_element *try_catch = &op_array->try_catch_array[i];
+
+ if (op_num < try_catch->try_op) {
+ break;
+ }
+
+ if (op_num < try_catch->finally_op) {
+ finally_op_num = try_catch->finally_op;
+ }
+ }
+
+ /* If a finally block was found we jump directly to it and
+ * resume the generator.. Furthermore we abort this close call
+ * because the generator will already be closed somewhere in
+ * the resume. */
+ if (finally_op_num) {
+ execute_data->opline = &op_array->opcodes[finally_op_num];
+ execute_data->leaving = ZEND_RETURN;
+ zend_generator_resume(generator TSRMLS_CC);
+ return;
+ }
+ }
+ }
+
if (!execute_data->symbol_table) {
zend_free_compiled_variables(execute_data->CVs, execute_data->op_array->last_var);
} else {
@@ -371,7 +404,7 @@ static zend_function *zend_generator_get_constructor(zval *object TSRMLS_DC) /*
}
/* }}} */
-static void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
+void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
{
/* The generator is already closed, thus can't resume */
if (!generator->execute_data) {
diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h
index f5f4926..37ffbbd 100644
--- a/Zend/zend_generators.h
+++ b/Zend/zend_generators.h
@@ -53,6 +53,7 @@ extern ZEND_API zend_class_entry *zend_ce_generator;
void zend_register_generator_ce(TSRMLS_D);
zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC);
void zend_generator_close(zend_generator *generator, zend_bool finished_execution TSRMLS_DC);
+void zend_generator_resume(zend_generator *generator TSRMLS_DC);
END_EXTERN_C()