Skip to content

Commit 970f21b

Browse files
committed
Fixed calling generators through magic __call()
1 parent fe04f54 commit 970f21b

File tree

3 files changed

+64
-20
lines changed

3 files changed

+64
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Calling generator through magic __call()
3+
--FILE--
4+
<?php
5+
class A {
6+
public function __call($name, $args) {
7+
for ($i = 0; $i < 5; $i++) {
8+
yield $i;
9+
}
10+
}
11+
}
12+
13+
$a = new A();
14+
foreach ($a->gen() as $n) {
15+
var_dump($n);
16+
}
17+
$a->gen();
18+
?>
19+
--EXPECT--
20+
int(0)
21+
int(1)
22+
int(2)
23+
int(3)
24+
int(4)

Zend/zend_vm_def.h

+20-10
Original file line numberDiff line numberDiff line change
@@ -7928,17 +7928,27 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
79287928

79297929
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
79307930

7931-
ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_GENERATOR));
7932-
7933-
call->symbol_table = NULL;
7934-
i_init_func_execute_data(call, &fbc->op_array,
7935-
ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
7936-
7937-
if (EXPECTED(zend_execute_ex == execute_ex)) {
7938-
ZEND_VM_ENTER();
7931+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
7932+
if (ret) {
7933+
zend_generator_create_zval(call, &fbc->op_array, ret);
7934+
Z_VAR_FLAGS_P(ret) = 0;
7935+
} else {
7936+
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
7937+
OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
7938+
}
7939+
zend_vm_stack_free_args(call);
7940+
}
79397941
} else {
7940-
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
7941-
zend_execute_ex(call);
7942+
call->symbol_table = NULL;
7943+
i_init_func_execute_data(call, &fbc->op_array,
7944+
ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
7945+
7946+
if (EXPECTED(zend_execute_ex == execute_ex)) {
7947+
ZEND_VM_ENTER();
7948+
} else {
7949+
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
7950+
zend_execute_ex(call);
7951+
}
79427952
}
79437953
} else {
79447954
zval retval;

Zend/zend_vm_execute.h

+20-10
Original file line numberDiff line numberDiff line change
@@ -1737,17 +1737,27 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
17371737

17381738
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
17391739

1740-
ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_GENERATOR));
1741-
1742-
call->symbol_table = NULL;
1743-
i_init_func_execute_data(call, &fbc->op_array,
1744-
ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
1745-
1746-
if (EXPECTED(zend_execute_ex == execute_ex)) {
1747-
ZEND_VM_ENTER();
1740+
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
1741+
if (ret) {
1742+
zend_generator_create_zval(call, &fbc->op_array, ret);
1743+
Z_VAR_FLAGS_P(ret) = 0;
1744+
} else {
1745+
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
1746+
OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
1747+
}
1748+
zend_vm_stack_free_args(call);
1749+
}
17481750
} else {
1749-
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
1750-
zend_execute_ex(call);
1751+
call->symbol_table = NULL;
1752+
i_init_func_execute_data(call, &fbc->op_array,
1753+
ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
1754+
1755+
if (EXPECTED(zend_execute_ex == execute_ex)) {
1756+
ZEND_VM_ENTER();
1757+
} else {
1758+
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
1759+
zend_execute_ex(call);
1760+
}
17511761
}
17521762
} else {
17531763
zval retval;

0 commit comments

Comments
 (0)