From 6418099826a408ba9a3b8dc1510deda80abef1a9 Mon Sep 17 00:00:00 2001 From: Yurun Date: Thu, 23 Jul 2026 21:41:47 +0800 Subject: [PATCH] =?UTF-8?q?fix(generator):=20=E6=8E=A5=E5=8F=97=20\Generat?= =?UTF-8?q?or=20=E4=BD=9C=E4=B8=BA=E5=90=88=E6=B3=95=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Generator/FiberGenerator.php | 6 +- .../generator/generator-foreach-yield.phpt | 57 +++++++++++++++++++ .../generator-return-type-generator.phpt | 53 +++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 tests/compiler/generator/generator-foreach-yield.phpt create mode 100644 tests/compiler/generator/generator-return-type-generator.phpt diff --git a/src/Generator/FiberGenerator.php b/src/Generator/FiberGenerator.php index a67f5870..9e766fd2 100644 --- a/src/Generator/FiberGenerator.php +++ b/src/Generator/FiberGenerator.php @@ -112,7 +112,11 @@ trait FiberGenerator [, $class] = $this->resolveTypeDecl($type, self::DECL_TYPE_OF_RETURN); $class = strtolower(ltrim($class, '\\')); - return in_array($class, ['iterator', 'traversable', 'fibergenerator'], true); + // `\Generator` is the return type PHP programmers naturally write for a + // generator. TypePHP generators actually return a `\FiberGenerator`, so + // accepting the declared `Generator` type keeps PHP source compatible + // while the runtime object remains a `\FiberGenerator`. + return in_array($class, ['iterator', 'traversable', 'fibergenerator', 'generator'], true); } protected function parseYieldExpr(Yield_ $expr): string diff --git a/tests/compiler/generator/generator-foreach-yield.phpt b/tests/compiler/generator/generator-foreach-yield.phpt new file mode 100644 index 00000000..d2029fc9 --- /dev/null +++ b/tests/compiler/generator/generator-foreach-yield.phpt @@ -0,0 +1,57 @@ +--TEST-- +generator re-yielding array elements via foreach with \Generator return type +--FILE-- + +--EXPECTF-- +object(FiberGenerator)#%d (9) { + ["callback":"FiberGenerator":private]=> + object(Closure)#%d (2) { + ["function"]=> + string(19) "stdClass::{closure}" + ["this"]=> + object(stdClass)#%d (1) { + ["box"]=> + resource(%d) of type (php::box) + } + } + ["fiber":"FiberGenerator":private]=> + NULL + ["current":"FiberGenerator":private]=> + NULL + ["key":"FiberGenerator":private]=> + NULL + ["valid":"FiberGenerator":private]=> + bool(false) + ["state":"FiberGenerator":private]=> + int(0) + ["yield_count":"FiberGenerator":private]=> + int(0) + ["next_index":"FiberGenerator":private]=> + int(0) + ["return_value":"FiberGenerator":private]=> + NULL +} +int(1) +int(2) +int(3) diff --git a/tests/compiler/generator/generator-return-type-generator.phpt b/tests/compiler/generator/generator-return-type-generator.phpt new file mode 100644 index 00000000..4d5894cc --- /dev/null +++ b/tests/compiler/generator/generator-return-type-generator.phpt @@ -0,0 +1,53 @@ +--TEST-- +generator return type accepts \Generator for methods, nullable and union variants +--FILE-- +gen([1, 2, 3]) as $v) { + var_dump($v); + } + $g = nullableGen([4, 5]); + foreach ($g as $v) { + var_dump($v); + } + $u = unionGen([6, 7]); + foreach ($u as $v) { + var_dump($v); + } +} +?> +--EXPECT-- +int(2) +int(4) +int(6) +int(4) +int(5) +int(6) +int(7)