feat(compiler): 添加闭包表达式支持

- 在 CompilerBase.php 中添加对 Expr_Closure 节点类型的解析处理
- 实现 parseClosure 方法来编译 PHP 闭包为 C++ 代码
- 添加临时变量生成和缩进级别管理逻辑
- 处理闭包参数和 use 子句中的变量捕获
- 验证闭包中使用的变量是否已定义
- 添加闭包示例文件 closure.php 和对应测试文件
- 修复 fcall.php 中的调试输出注释问题
pull/1/head
韩天峰 7 months ago
parent 60ba3da404
commit f2e7b70043
  1. 14
      examples/closure.php
  2. 3
      examples/fcall.php
  3. 39
      src/Php/CompilerBase.php
  4. 28
      tests/aot/closure-001.phpt

@ -0,0 +1,14 @@
<?php
function main(): int
{
$a = 100;
$b = [1, 2, 3];
$fn = function ($x) use ($a, $b)
{
var_dump($a);
var_dump($b);
var_dump($x);
};
$fn(1000);
return 0;
}

@ -17,4 +17,7 @@ function main()
{ {
$o = new A; $o = new A;
$o->foo(1, 2); $o->foo(1, 2);
var_dump($xxx);
// var_dump($arr2['hello']);
// var_dump($o2->null);
} }

@ -375,6 +375,8 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->parseThrow($expr); return $this->parseThrow($expr);
case 'Expr_ShellExec': case 'Expr_ShellExec':
return $this->parseShellExec($expr); return $this->parseShellExec($expr);
case 'Expr_Closure':
return $this->parseClosure($expr);
case 'Name_FullyQualified': case 'Name_FullyQualified':
return $expr->name; return $expr->name;
case 'Scalar_Int': case 'Scalar_Int':
@ -3427,4 +3429,41 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
return $code; return $code;
} }
protected function parseClosure(Node\Expr\Closure $expr): string
{
$tmpVar = $this->genTmpVarName();
$fnCode = $this->getIndent() . 'php::ClosureFn ' . $tmpVar . ' = [](INTERNAL_FUNCTION_PARAMETERS, ' . self::TYPE_OBJECT . ' &this_, ' . self::TYPE_ARRAY . ' &vars_) {' . PHP_EOL;
$oriLocalVars = $this->localVars;
$this->localVars = [];
$this->indentLevel++;
foreach ($expr->params as $i => $param) {
$var = $this->parseIdentifier($param->var);
$fnCode .= 'auto ' . $var . ' = php::getCallArg(' . $i . ');' . PHP_EOL;
$this->addLocalVar($var, self::TYPE_VAR);
}
foreach ($expr->uses as $i => $useItem) {
$var = $this->parseIdentifier($useItem->var);
$fnCode .= 'auto ' . $var . ' = vars_.get(' . $i . ');' . PHP_EOL;
$this->addLocalVar($var, self::TYPE_VAR);
}
$fnCode .= $this->parseStmts($expr->stmts);
$this->indentLevel--;
$fnCode .= '};' . PHP_EOL;
$this->beforeStmtLines[] = $fnCode;
$this->localVars = $oriLocalVars;
$useVars = [];
foreach ($expr->uses as $useItem) {
$var = $this->parseIdentifier($useItem->var);
if ($this->isVarExpr($useItem->var) and !$this->hasVar($var)) {
$this->fatalError($expr, 'Variable `' . $var . '` is not defined');
}
$useVars [] = $var;
}
return 'php::newClosure(' . $tmpVar . ', { ' . implode(', ', $useVars) . ' })';
}
} }

@ -0,0 +1,28 @@
--TEST--
closure 001
--FILE--
<?php
function main()
{
$a = 100;
$b = [1, 2, 3];
$fn = function ($x) use ($a, $b) {
var_dump($a);
var_dump($b);
var_dump($x);
};
$fn(1000);
}
?>
--EXPECT--
int(100)
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
int(1000)
Loading…
Cancel
Save