diff --git a/examples/closure.php b/examples/closure.php new file mode 100644 index 00000000..853c4599 --- /dev/null +++ b/examples/closure.php @@ -0,0 +1,14 @@ +foo(1, 2); + var_dump($xxx); +// var_dump($arr2['hello']); +// var_dump($o2->null); } diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 60c4beee..843b9277 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -375,6 +375,8 @@ class CompilerBase extends \PhpAot\Core\Translator return $this->parseThrow($expr); case 'Expr_ShellExec': return $this->parseShellExec($expr); + case 'Expr_Closure': + return $this->parseClosure($expr); case 'Name_FullyQualified': return $expr->name; case 'Scalar_Int': @@ -3427,4 +3429,41 @@ class CompilerBase extends \PhpAot\Core\Translator } 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) . ' })'; + } } diff --git a/tests/aot/closure-001.phpt b/tests/aot/closure-001.phpt new file mode 100644 index 00000000..3fcaba99 --- /dev/null +++ b/tests/aot/closure-001.phpt @@ -0,0 +1,28 @@ +--TEST-- +closure 001 +--FILE-- + +--EXPECT-- +int(100) +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +} +int(1000) +