Skip to content

Commit 8094bd1

Browse files
authored
Make ReflectionGenerator::getFunction() legal after generator termination (#14167)
* Make `ReflectionGenerator::getFunction()` legal after generator termination * Expose the generator function name via `Generator::__debugInfo()` * Allow creating `ReflectionGenerator` after termination * Reorder `struct _zend_generator` to avoid a hole * Adjust `ext/reflection/tests/028.phpt` This is legal now. * Fix Generator Closure collection * Add test to verify the Closure dies with the generator * NEWS / UPGRADING
1 parent 14b92d5 commit 8094bd1

24 files changed

+367
-58
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ PHP NEWS
207207
- Reflection:
208208
. Implement GH-12908 (Show attribute name/class in ReflectionAttribute dump).
209209
(nielsdos)
210+
. Make ReflectionGenerator::getFunction() legal after generator termination.
211+
(timwolla)
210212

211213
- SimpleXML:
212214
. Fixed bug GH-12192 (SimpleXML infinite loop when getName() is called

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,10 @@ PHP 8.4 UPGRADE NOTES
437437
. posix_isatty now sets the error number when the file descriptor/stream argument
438438
is invalid.
439439

440+
- Reflection:
441+
. ReflectionGenerator::getFunction() may now be called after the generator
442+
finished executing.
443+
440444
- Sockets:
441445
. Parameter $backlog of socket_create_listen() now has a default value of SOMAXCONN.
442446
Previously, it was 128.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
--TEST--
2+
Generators expose the underlying function name in __debugInfo().
3+
--FILE--
4+
<?php
5+
6+
function foo() {
7+
yield;
8+
}
9+
10+
$gens = [
11+
(new class() {
12+
function a() {
13+
yield from foo();
14+
}
15+
})->a(),
16+
(function() {
17+
yield;
18+
})(),
19+
foo(),
20+
];
21+
22+
foreach ($gens as $gen) {
23+
echo "Before:", PHP_EOL;
24+
var_dump($gen);
25+
26+
foreach ($gen as $dummy) {
27+
echo "Inside:", PHP_EOL;
28+
var_dump($gen);
29+
}
30+
31+
echo "After:", PHP_EOL;
32+
33+
var_dump($gen);
34+
}
35+
36+
?>
37+
--EXPECTF--
38+
Before:
39+
object(Generator)#%d (1) {
40+
["function"]=>
41+
string(%d) "class@anonymous%s::a"
42+
}
43+
Inside:
44+
object(Generator)#%d (1) {
45+
["function"]=>
46+
string(%d) "class@anonymous%s::a"
47+
}
48+
After:
49+
object(Generator)#%d (1) {
50+
["function"]=>
51+
string(%d) "class@anonymous%s::a"
52+
}
53+
Before:
54+
object(Generator)#%d (1) {
55+
["function"]=>
56+
string(%d) "{closure:%s:%d}"
57+
}
58+
Inside:
59+
object(Generator)#%d (1) {
60+
["function"]=>
61+
string(%d) "{closure:%s:%d}"
62+
}
63+
After:
64+
object(Generator)#%d (1) {
65+
["function"]=>
66+
string(%d) "{closure:%s:%d}"
67+
}
68+
Before:
69+
object(Generator)#%d (1) {
70+
["function"]=>
71+
string(3) "foo"
72+
}
73+
Inside:
74+
object(Generator)#%d (1) {
75+
["function"]=>
76+
string(3) "foo"
77+
}
78+
After:
79+
object(Generator)#%d (1) {
80+
["function"]=>
81+
string(3) "foo"
82+
}

Zend/tests/generators/gc_with_yield_from.phpt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,29 @@ gc_collect_cycles();
2727
print "end\n";
2828

2929
?>
30-
--EXPECT--
30+
--EXPECTF--
3131
int(1)
3232
collect
3333
array(4) {
3434
[0]=>
35-
object(Generator)#1 (0) {
35+
object(Generator)#%d (1) {
36+
["function"]=>
37+
string(3) "gen"
3638
}
3739
[1]=>
38-
object(Generator)#2 (0) {
40+
object(Generator)#%d (1) {
41+
["function"]=>
42+
string(3) "gen"
3943
}
4044
[2]=>
41-
object(Generator)#3 (0) {
45+
object(Generator)#%d (1) {
46+
["function"]=>
47+
string(3) "gen"
4248
}
4349
[3]=>
44-
object(Generator)#4 (0) {
50+
object(Generator)#%d (1) {
51+
["function"]=>
52+
string(4) "root"
4553
}
4654
}
4755
end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
The Closure object of a generator is freed when the generator is freed.
3+
--FILE--
4+
<?php
5+
6+
$genFactory = function() {
7+
yield 1;
8+
yield 2;
9+
yield 3;
10+
};
11+
12+
$r = WeakReference::create($genFactory);
13+
$generator = $genFactory();
14+
unset($genFactory);
15+
16+
var_dump($r->get());
17+
18+
foreach ($generator as $value) var_dump($value);
19+
20+
var_dump($r->get());
21+
22+
unset($generator);
23+
24+
var_dump($r->get());
25+
26+
?>
27+
--EXPECTF--
28+
object(Closure)#%d (3) {
29+
["name"]=>
30+
string(%d) "{closure:%s:%d}"
31+
["file"]=>
32+
string(%d) "%s"
33+
["line"]=>
34+
int(%d)
35+
}
36+
int(1)
37+
int(2)
38+
int(3)
39+
object(Closure)#%d (3) {
40+
["name"]=>
41+
string(%d) "{closure:%s:%d}"
42+
["file"]=>
43+
string(%d) "%s"
44+
["line"]=>
45+
int(%d)
46+
}
47+
NULL

Zend/tests/generators/generator_return_without_value.phpt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,19 @@ var_dump(gen4());
3333

3434
?>
3535
--EXPECTF--
36-
object(Generator)#%d (0) {
36+
object(Generator)#%d (1) {
37+
["function"]=>
38+
string(3) "gen"
3739
}
38-
object(Generator)#%d (0) {
40+
object(Generator)#%d (1) {
41+
["function"]=>
42+
string(4) "gen2"
3943
}
40-
object(Generator)#%d (0) {
44+
object(Generator)#%d (1) {
45+
["function"]=>
46+
string(4) "gen3"
4147
}
42-
object(Generator)#%d (0) {
48+
object(Generator)#%d (1) {
49+
["function"]=>
50+
string(4) "gen4"
4351
}

Zend/tests/return_types/generators001.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,30 @@ var_dump(
4242
?>
4343
--EXPECTF--
4444
object(Generator)#%d (%d) {
45+
["function"]=>
46+
string(5) "test1"
4547
}
4648
object(Generator)#%d (%d) {
49+
["function"]=>
50+
string(5) "test2"
4751
}
4852
object(Generator)#%d (%d) {
53+
["function"]=>
54+
string(5) "test3"
4955
}
5056
object(Generator)#%d (%d) {
57+
["function"]=>
58+
string(5) "test4"
5159
}
5260
object(Generator)#%d (%d) {
61+
["function"]=>
62+
string(5) "test5"
5363
}
5464
object(Generator)#%d (%d) {
65+
["function"]=>
66+
string(5) "test6"
5567
}
5668
object(Generator)#%d (%d) {
69+
["function"]=>
70+
string(5) "test7"
5771
}

Zend/tests/return_types/generators005.phpt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ var_dump($some->getIterator());
1919
?>
2020
--EXPECTF--
2121
object(Generator)#%d (%d) {
22+
["function"]=>
23+
string(27) "SomeCollection::getIterator"
2224
}

Zend/tests/type_declarations/iterable/iterable_001.phpt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ array(3) {
3232
[2]=>
3333
int(3)
3434
}
35-
object(Generator)#1 (0) {
35+
object(Generator)#%d (1) {
36+
["function"]=>
37+
string(3) "gen"
3638
}
3739
object(ArrayIterator)#1 (1) {
3840
["storage":"ArrayIterator":private]=>

Zend/tests/type_declarations/iterable/iterable_003.phpt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ try {
2424
}
2525

2626
?>
27-
--EXPECT--
27+
--EXPECTF--
2828
array(0) {
2929
}
30-
object(Generator)#2 (0) {
30+
object(Generator)#%d (1) {
31+
["function"]=>
32+
string(17) "{closure:bar():7}"
3133
}
3234
baz(): Return value must be of type Traversable|array, int returned

0 commit comments

Comments
 (0)