Skip to content

PHP 5.5 generator exception #242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions Zend/tests/generators/raise_deep.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--TEST--
Raise exception in the generator
--FILE--
<?php
function gen() {
var_dump("start generator");
try {
var_dump(yield gen2());
} catch(Exception $e) {
var_dump($e->getMessage());
throw $e;
}
var_dump(yield "yield bar");
}

function gen2() {
var_dump("start sub generator");

var_dump(yield "yield foo");
}

$gen = gen();
var_dump($gen->current());
$gen->raise(new Exception("raise exception"));
var_dump($gen->current());
$gen->send("send foo");

?>
--EXPECT--
string(15) "start generator"
string(9) "yield foo"
string(14) "raise exception"
string(14) "exception dtor"
string(9) "yield bar"
string(8) "send foo"
35 changes: 35 additions & 0 deletions Zend/tests/generators/raise_exception.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--TEST--
Raise exception in the generator
--FILE--
<?php
class ExceptionEx extends Exception {
public function __destruct() {
var_dump("exception dtor");
}
}
function gen() {
var_dump("start generator");
try {
var_dump(yield "yield foo");
var_dump("throws failed");
} catch(Exception $e) {
var_dump($e->getMessage());
unset($e);
}
var_dump(yield "yield bar");
}

$gen = gen();
var_dump($gen->current());
$gen->raise(new ExceptionEx("raise exception"));
var_dump($gen->current());
$gen->send("send foo");

?>
--EXPECT--
string(15) "start generator"
string(9) "yield foo"
string(15) "raise exception"
string(14) "exception dtor"
string(9) "yield bar"
string(8) "send foo"
32 changes: 32 additions & 0 deletions Zend/tests/generators/raise_unexpected_exception.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
Raise exception in the generator
--FILE--
<?php
function gen() {
var_dump("start generator");
var_dump(yield "yield foo");
try {

var_dump("throws failed");
} catch(Exception $e) {
var_dump("catch");
throw $e;
}

var_dump(yield "yield bar");
}

$gen = gen();
var_dump($gen->current());
$gen->raise(new Exception("raise exception"));
var_dump($gen->current());
$gen->send("send foo");

?>
--EXPECT--
string(15) "start generator"
string(9) "yield foo"
string(14) "raise exception"
string(14) "exception dtor"
string(9) "yield bar"
string(8) "send foo"
48 changes: 48 additions & 0 deletions Zend/zend_generators.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,12 @@ void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
* set the prev_execute_data of that prev_execute_data :) */
generator->execute_data->prev_execute_data->prev_execute_data = original_execute_data;

if(generator->exception) {
EG(exception) = generator->exception;
generator->exception = NULL;
zend_throw_exception_internal(NULL TSRMLS_CC);
}

/* Resume execution */
generator->flags |= ZEND_GENERATOR_CURRENTLY_RUNNING;
zend_execute_ex(generator->execute_data TSRMLS_CC);
Expand Down Expand Up @@ -623,6 +629,43 @@ ZEND_METHOD(Generator, send)
}
/* }}} */

/* {{{ proto mixed Generator::raise()
* Throw exception into the generator */
ZEND_METHOD(Generator, raise)
{
zval *exc;
zend_generator *generator;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &exc) == FAILURE) {
return;
}

generator = (zend_generator *) zend_object_store_get_object(getThis() TSRMLS_CC);

if(generator->exception) {
zval_ptr_dtor(&(generator->exception));
}

ALLOC_INIT_ZVAL(generator->exception);
ZVAL_ZVAL(generator->exception, exc, 1, 0);
//generator->exception = exc;
zend_generator_ensure_initialized(generator TSRMLS_CC);

/* The generator is already closed, thus can't send anything */
if (!generator->execute_data) {
return;
}

/* The sent value was initialized to NULL, so dtor that */
zval_ptr_dtor(&generator->send_target->var.ptr);

zend_generator_resume(generator TSRMLS_CC);

if (generator->value) {
RETURN_ZVAL(generator->value, 1, 0);
}
}
/* }}} */

/* {{{ proto void Generator::__wakeup()
* Throws an Exception as generators can't be serialized */
ZEND_METHOD(Generator, __wakeup)
Expand Down Expand Up @@ -764,13 +807,18 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_send, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_generator_raise, 0, 0, 1)
ZEND_ARG_INFO(0, exception)
ZEND_END_ARG_INFO()

static const zend_function_entry generator_functions[] = {
ZEND_ME(Generator, rewind, arginfo_generator_void, ZEND_ACC_PUBLIC)
ZEND_ME(Generator, valid, arginfo_generator_void, ZEND_ACC_PUBLIC)
ZEND_ME(Generator, current, arginfo_generator_void, ZEND_ACC_PUBLIC)
ZEND_ME(Generator, key, arginfo_generator_void, ZEND_ACC_PUBLIC)
ZEND_ME(Generator, next, arginfo_generator_void, ZEND_ACC_PUBLIC)
ZEND_ME(Generator, send, arginfo_generator_send, ZEND_ACC_PUBLIC)
ZEND_ME(Generator, raise, arginfo_generator_raise, ZEND_ACC_PUBLIC)
ZEND_ME(Generator, __wakeup, arginfo_generator_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
Expand Down
5 changes: 4 additions & 1 deletion Zend/zend_generators.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@ typedef struct _zend_generator {

/* The separate stack used by generator */
zend_vm_stack stack;

/* Current value */
zval *value;
/* Current key */
zval *key;

zval *exception;
/* Variable to put sent value into */
temp_variable *send_target;
/* Largest used integer key for auto-incrementing keys */
Expand All @@ -60,6 +62,7 @@ typedef struct _zend_generator {
static const zend_uchar ZEND_GENERATOR_CURRENTLY_RUNNING = 0x1;
static const zend_uchar ZEND_GENERATOR_FORCED_CLOSE = 0x2;
static const zend_uchar ZEND_GENERATOR_AT_FIRST_YIELD = 0x4;
static const zend_uchar ZEND_GENERATOR_RISE_EXCEPTION = 0x8;

void zend_register_generator_ce(TSRMLS_D);
zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC);
Expand Down