fix(generator): 接受 \Generator 作为合法返回类型

pull/32/head
Yurun 1 month ago
parent 2287695b44
commit 6418099826
  1. 6
      src/Generator/FiberGenerator.php
  2. 57
      tests/compiler/generator/generator-foreach-yield.phpt
  3. 53
      tests/compiler/generator/generator-return-type-generator.phpt

@ -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

@ -0,0 +1,57 @@
--TEST--
generator re-yielding array elements via foreach with \Generator return type
--FILE--
<?php
function main()
{
$g = test([1, 2, 3]);
var_dump($g);
foreach ($g as $value)
{
var_dump($value);
}
}
function test(array $array): \Generator
{
foreach ($array as $value)
{
yield $value;
}
}
// main();
?>
--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)

@ -0,0 +1,53 @@
--TEST--
generator return type accepts \Generator for methods, nullable and union variants
--FILE--
<?php
class Box
{
public function gen(array $array): \Generator
{
foreach ($array as $value) {
yield $value * 2;
}
}
}
function nullableGen(array $array): ?\Generator
{
foreach ($array as $value) {
yield $value;
}
}
function unionGen(array $array): \Generator|\Iterator
{
foreach ($array as $value) {
yield $value;
}
}
function main()
{
$b = new Box();
foreach ($b->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)
Loading…
Cancel
Save