mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Implement Generator::throw() method
Generator::throw($exception) throws an exception into the generator. The exception is thrown at the current point of suspension within the generator. It basically behaves as if the current yield statement were replaced with a throw statement and the generator subsequently resumed.
This commit is contained in:
parent
24f1ef1b02
commit
be7b0bc3ec
1
NEWS
1
NEWS
@ -5,6 +5,7 @@ PHP NEWS
|
||||
- General improvements:
|
||||
. Fixed bug #63822 (Crash when using closures with ArrayAccess).
|
||||
(Nikita Popov)
|
||||
. Add Generator::throw() method. (Nikita Popov)
|
||||
|
||||
- cURL:
|
||||
. Added new functions curl_escape, curl_multi_setopt, curl_multi_strerror
|
||||
|
23
Zend/tests/generators/throw_already_closed.phpt
Normal file
23
Zend/tests/generators/throw_already_closed.phpt
Normal file
@ -0,0 +1,23 @@
|
||||
--TEST--
|
||||
Generator::throw() on an already closed generator
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen() {
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen();
|
||||
$gen->next();
|
||||
$gen->next();
|
||||
var_dump($gen->valid());
|
||||
$gen->throw(new Exception('test'));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
bool(false)
|
||||
|
||||
Fatal error: Uncaught exception 'Exception' with message 'test' in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
25
Zend/tests/generators/throw_caught.phpt
Normal file
25
Zend/tests/generators/throw_caught.phpt
Normal file
@ -0,0 +1,25 @@
|
||||
--TEST--
|
||||
Generator::throw() where the exception is caught in the generator
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen() {
|
||||
try {
|
||||
yield;
|
||||
} catch (RuntimeException $e) {
|
||||
echo $e, "\n\n";
|
||||
}
|
||||
|
||||
yield 'result';
|
||||
}
|
||||
|
||||
$gen = gen();
|
||||
var_dump($gen->throw(new RuntimeException('Test')));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
exception 'RuntimeException' with message 'Test' in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
|
||||
string(6) "result"
|
15
Zend/tests/generators/throw_not_an_exception.phpt
Normal file
15
Zend/tests/generators/throw_not_an_exception.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
Generator::throw() with something that's not an exception
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen() {
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen();
|
||||
$gen->throw(new stdClass);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Exceptions must be valid objects derived from the Exception base class in %s on line %d
|
32
Zend/tests/generators/throw_rethrow.phpt
Normal file
32
Zend/tests/generators/throw_rethrow.phpt
Normal file
@ -0,0 +1,32 @@
|
||||
--TEST--
|
||||
Generator::throw() where the generator throws a different exception
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen() {
|
||||
try {
|
||||
yield;
|
||||
} catch (RuntimeException $e) {
|
||||
echo 'Caught: ', $e, "\n\n";
|
||||
|
||||
throw new LogicException('new throw');
|
||||
}
|
||||
}
|
||||
|
||||
$gen = gen();
|
||||
var_dump($gen->throw(new RuntimeException('throw')));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Caught: exception 'RuntimeException' with message 'throw' in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
|
||||
|
||||
Fatal error: Uncaught exception 'LogicException' with message 'new throw' in %s:%d
|
||||
Stack trace:
|
||||
#0 [internal function]: gen()
|
||||
#1 %s(%d): Generator->throw(Object(RuntimeException))
|
||||
#2 {main}
|
||||
thrown in %s on line %d
|
||||
|
19
Zend/tests/generators/throw_uncaught.phpt
Normal file
19
Zend/tests/generators/throw_uncaught.phpt
Normal file
@ -0,0 +1,19 @@
|
||||
--TEST--
|
||||
Generator::throw() where the exception is not caught in the generator
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen() {
|
||||
yield 'thisThrows';
|
||||
yield 'notReached';
|
||||
}
|
||||
|
||||
$gen = gen();
|
||||
var_dump($gen->throw(new RuntimeException('test')));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Uncaught exception 'RuntimeException' with message 'test' in %s:%d
|
||||
Stack trace:
|
||||
#0 {main}
|
||||
thrown in %s on line %d
|
@ -431,10 +431,6 @@ static zend_function *zend_generator_get_constructor(zval *object TSRMLS_DC) /*
|
||||
|
||||
ZEND_API void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (EG(exception)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* The generator is already closed, thus can't resume */
|
||||
if (!generator->execute_data) {
|
||||
return;
|
||||
@ -617,7 +613,7 @@ ZEND_METHOD(Generator, next)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto mixed Generator::send()
|
||||
/* {{{ proto mixed Generator::send(mixed $value)
|
||||
* Sends a value to the generator */
|
||||
ZEND_METHOD(Generator, send)
|
||||
{
|
||||
@ -648,6 +644,44 @@ ZEND_METHOD(Generator, send)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto mixed Generator::throw(Exception $exception)
|
||||
* Throws an exception into the generator */
|
||||
ZEND_METHOD(Generator, throw)
|
||||
{
|
||||
zval *exception, *exception_copy;
|
||||
zend_generator *generator;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &exception) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
ALLOC_ZVAL(exception_copy);
|
||||
MAKE_COPY_ZVAL(&exception, exception_copy);
|
||||
|
||||
generator = (zend_generator *) zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
|
||||
if (generator->execute_data) {
|
||||
/* Throw the exception in the context of the generator */
|
||||
zend_execute_data *current_execute_data = EG(current_execute_data);
|
||||
EG(current_execute_data) = generator->execute_data;
|
||||
|
||||
zend_throw_exception_object(exception_copy TSRMLS_CC);
|
||||
|
||||
EG(current_execute_data) = current_execute_data;
|
||||
|
||||
zend_generator_resume(generator TSRMLS_CC);
|
||||
|
||||
if (generator->value) {
|
||||
RETURN_ZVAL(generator->value, 1, 0);
|
||||
}
|
||||
} else {
|
||||
/* If the generator is already closed throw the exception in the
|
||||
* current context */
|
||||
zend_throw_exception_object(exception_copy TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void Generator::__wakeup()
|
||||
* Throws an Exception as generators can't be serialized */
|
||||
ZEND_METHOD(Generator, __wakeup)
|
||||
@ -790,6 +824,10 @@ 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_throw, 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)
|
||||
@ -797,6 +835,7 @@ static const zend_function_entry generator_functions[] = {
|
||||
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, throw, arginfo_generator_throw, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(Generator, __wakeup, arginfo_generator_void, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user