From 67427f342df8c6807099f5fd54bc62ef58c78548 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 10 Feb 2026 17:55:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(closure):=20=E6=B7=BB=E5=8A=A0=E9=97=AD?= =?UTF-8?q?=E5=8C=85=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81=E5=B9=B6=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E7=9B=B8=E5=85=B3=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了嵌套lambda表达式的支持,实现类中的闭包嵌套功能 - 实现了preg_replace_callback中lambda表达式的使用场景 - 支持在lambda内部使用静态变量的功能 - 完善了闭包自调用的实现逻辑 - 添加了四个新的闭包测试用例(closure_007-010) - 在编译器基类中增加了inClosure状态标识 - 修复了return语句在闭包中的处理逻辑 - 更新了闭包函数体的返回值处理方式 --- src/Php/CompilerBase.php | 12 ++++++-- tests/zend/closures/closure_007.phpt | 41 ++++++++++++++++++++++++++++ tests/zend/closures/closure_008.phpt | 24 ++++++++++++++++ tests/zend/closures/closure_009.phpt | 33 ++++++++++++++++++++++ tests/zend/closures/closure_010.phpt | 20 ++++++++++++++ 5 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 tests/zend/closures/closure_007.phpt create mode 100644 tests/zend/closures/closure_008.phpt create mode 100644 tests/zend/closures/closure_009.phpt create mode 100644 tests/zend/closures/closure_010.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 3d0de88c..afdd96da 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -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) { diff --git a/tests/zend/closures/closure_007.phpt b/tests/zend/closures/closure_007.phpt new file mode 100644 index 00000000..21aec8b9 --- /dev/null +++ b/tests/zend/closures/closure_007.phpt @@ -0,0 +1,41 @@ +--TEST-- +Closure 007: Nested lambdas in classes +--FILE-- +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 diff --git a/tests/zend/closures/closure_008.phpt b/tests/zend/closures/closure_008.phpt new file mode 100644 index 00000000..bb226dfd --- /dev/null +++ b/tests/zend/closures/closure_008.phpt @@ -0,0 +1,24 @@ +--TEST-- +Closure 008: Use in preg_replace_callback() +--FILE-- + +--EXPECT-- +1 2 3 +1  2  3 +1   2   3 +Done diff --git a/tests/zend/closures/closure_009.phpt b/tests/zend/closures/closure_009.phpt new file mode 100644 index 00000000..c6881d59 --- /dev/null +++ b/tests/zend/closures/closure_009.phpt @@ -0,0 +1,33 @@ +--TEST-- +Closure 009: Using static vars inside lambda +--FILE-- + +--EXPECT-- +1:1:1 +2:2:1 +3:3:1 +4:1:1 +5:2:1:1 +6:3:2:1:1 diff --git a/tests/zend/closures/closure_010.phpt b/tests/zend/closures/closure_010.phpt new file mode 100644 index 00000000..04516f6a --- /dev/null +++ b/tests/zend/closures/closure_010.phpt @@ -0,0 +1,20 @@ +--TEST-- +Closure 010: Closure calls itself +--FILE-- + +--EXPECT-- +3 +2 +1 +0