feat(closure): 添加闭包功能支持并完善相关测试用例

- 添加了嵌套lambda表达式的支持,实现类中的闭包嵌套功能
- 实现了preg_replace_callback中lambda表达式的使用场景
- 支持在lambda内部使用静态变量的功能
- 完善了闭包自调用的实现逻辑
- 添加了四个新的闭包测试用例(closure_007-010)
- 在编译器基类中增加了inClosure状态标识
- 修复了return语句在闭包中的处理逻辑
- 更新了闭包函数体的返回值处理方式
pull/1/head
韩天峰 7 months ago
parent be22aa751f
commit 67427f342d
  1. 12
      src/Php/CompilerBase.php
  2. 41
      tests/zend/closures/closure_007.phpt
  3. 24
      tests/zend/closures/closure_008.phpt
  4. 33
      tests/zend/closures/closure_009.phpt
  5. 20
      tests/zend/closures/closure_010.phpt

@ -191,6 +191,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected array $beforeStmtLines = [];
protected array $afterStmtLines = [];
protected bool $inLoop = false;
protected bool $inClosure = false;
/**
* 赋值表达式的左值,写操作,右值为读操作.
@ -895,7 +896,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$result = $this->parseEcho($v);
break;
case 'Stmt_Return':
$result = $this->parseReturn($v) . ';';
$result = $this->parseReturn($v);
break;
case 'Stmt_For':
$this->inLoop = true;
@ -1244,7 +1245,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseReturn(mixed $v): string
{
if ($v->expr === null) {
if ($this->functionDef->returnType === self::TYPE_VOID) {
if ($this->functionDef->returnType === self::TYPE_VOID and !$this->inClosure) {
return 'return;';
} else {
return 'return ' . self::VALUE_NULL . ';';
@ -3522,10 +3523,14 @@ class CompilerBase extends \PhpAot\Core\Translator
. self::TYPE_OBJECT . ' &this_, '
. self::TYPE_ARGS . ' &vars_) ' .
'-> ' . self::TYPE_VAR . ' {' . PHP_EOL;
$oriLocalVars = $this->localVars;
$this->localVars = [];
$oriArgs = $this->arguments;
$this->arguments = [];
$oriInClosure = $this->inClosure;
$this->inClosure = true;
$this->indentLevel++;
$fnBodyCode = '';
@ -3550,7 +3555,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$fnCode .= $fnBodyCode;
if (!$this->isReturnStmtInLastLine($expr->stmts)) {
$fnCode .= 'return '.self::VALUE_NAN. ';' . PHP_EOL;
$fnCode .= 'return ' . self::VALUE_NULL . ';' . PHP_EOL;
}
$this->indentLevel--;
@ -3559,6 +3564,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->beforeStmtLines[] = $fnCode;
$this->localVars = $oriLocalVars;
$this->arguments = $oriArgs;
$this->inClosure = $oriInClosure;
$useVars = [];
foreach ($expr->uses as $useItem) {

@ -0,0 +1,41 @@
--TEST--
Closure 007: Nested lambdas in classes
--FILE--
<?php
class A {
private $x = 0;
function getClosureGetter () {
return function () {
return function () {
$this->x++;
};
};
}
function printX () {
echo $this->x."\n";
}
}
function main() {
$a = new A;
$a->printX();
$getClosure = $a->getClosureGetter();
$a->printX();
$closure = $getClosure();
$a->printX();
$closure();
$a->printX();
echo "Done\n";
}
?>
--EXPECT--
0
0
0
1
Done

@ -0,0 +1,24 @@
--TEST--
Closure 008: Use in preg_replace_callback()
--FILE--
<?php
function replace_spaces($text) {
$lambda = function ($matches) {
return str_replace(' ', '&nbsp;', $matches[1]).' ';
};
return preg_replace_callback('/( +) /', $lambda, $text);
}
function main() {
echo replace_spaces("1 2 3\n");
echo replace_spaces("1 2 3\n");
echo replace_spaces("1 2 3\n");
echo "Done\n";
}
?>
--EXPECT--
1 2 3
1&nbsp; 2&nbsp; 3
1&nbsp;&nbsp; 2&nbsp;&nbsp; 3
Done

@ -0,0 +1,33 @@
--TEST--
Closure 009: Using static vars inside lambda
--FILE--
<?php
function main() {
$a = 1;
$x = function ($x) use ($a) {
static $n = 0;
$n++;
$a = $n.':'.$a;
echo $x.':'.$a."\n";
};
$y = function ($x) use (&$a) {
static $n = 0;
$n++;
$a = $n.':'.$a;
echo $x.':'.$a."\n";
};
$x(1);
$x(2);
$x(3);
$y(4);
$y(5);
$y(6);
}
?>
--EXPECT--
1:1:1
2:2:1
3:3:1
4:1:1
5:2:1:1
6:3:2:1:1

@ -0,0 +1,20 @@
--TEST--
Closure 010: Closure calls itself
--FILE--
<?php
function main() {
$i = 3;
$lambda = function ($lambda) use (&$i) {
if ($i==0) return;
echo $i--."\n";
$lambda($lambda);
};
$lambda($lambda);
echo "$i\n";
}
?>
--EXPECT--
3
2
1
0
Loading…
Cancel
Save