refactor(closure): 移除闭包生成器中的当前作用域参数

- 移除了 genClosure 方法中的 $useCurrentScope 参数
- 简化了闭包捕获逻辑,统一使用默认捕获方式
- 移除了条件性的上下文切换逻辑
- 简化了变量引用处理逻辑
- 在箭头函数解析中添加了变量查找和 use 子句生成功能
- 修复了闭包参数引用检查和变量作用域处理
pull/1/head
韩天峰 5 months ago
parent 1b8a2fb19d
commit 94615f939a
  1. 25
      src/Php/CompilerBase.php
  2. 34
      src/Php/Generator/ClosureGenerator.php
  3. 0
      tests/aot/arrow_fn/001.phpt
  4. 0
      tests/aot/arrow_fn/002.phpt
  5. 0
      tests/aot/arrow_fn/003.phpt

@ -34,6 +34,7 @@ use PhpParser\Node\Scalar\MagicConst;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\UnionType;
use PhpParser\NodeAbstract;
use PhpParser\NodeFinder;
use PhpParser\Parser;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
@ -4300,6 +4301,27 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseArrowFunction(Node\Expr\ArrowFunction $expr): string
{
$nodeFinder = new NodeFinder();
$vars = $nodeFinder->findInstanceOf($expr->expr, Node\Expr\Variable::class);
$uses = [];
$params = [];
foreach ($expr->params as $i => $param) {
if ($param->byRef) {
$this->fatalError($expr, 'Closure cannot use reference parameter');
}
if ($param->var instanceof Node\Expr\Variable) {
$params[$param->var->name] = $i;
}
}
foreach ($vars as $var) {
if ($var->name === 'this' or !$this->hasLocalVar($var->name) or isset($params[$var->name])) {
continue;
}
$uses[] = new Node\ClosureUse($var);
}
$cb = function () use ($expr) {
$code = $this->parseExpr($expr->expr);
if ($this->context->beforeStmtLines) {
@ -4315,7 +4337,8 @@ class CompilerBase extends \PhpAot\Core\Translator
}
return $beforeCode . PHP_EOL . 'return ' . $code . ';';
};
return $this->genClosure($expr, $expr->params, $cb, [], true);
return $this->genClosure($expr, $expr->params, $cb, $uses);
}
protected function parseClosure(Node\Expr\Closure $expr): string

@ -22,29 +22,25 @@ trait ClosureGenerator
}
/**
* @param $useCurrentScope bool 直接使用当前作用域,C++ 函数将使用 & 捕获所有闭包变量
* @param NodeAbstract $expr
* @param array $params
* @param callable $bodyGenCb
* @param array $uses
* @return string
*/
protected function genClosure(NodeAbstract $expr, array $params, callable $bodyGenCb, array $uses = [], bool $useCurrentScope = false): string
protected function genClosure(NodeAbstract $expr, array $params, callable $bodyGenCb, array $uses = []): string
{
$tmpVar = $this->genTmpVarName();
// 必须使用 = 捕获,不能使用 & ,否则可能会出现悬空指针
// 在 PHP 中 = 赋值是浅拷贝,仅增加一次引用计数,和 zval (16 字节) 封装的赋值
$capture = $useCurrentScope ? '&' : '';
$code = $this->getIndent() .
'php::ClosureFn ' . $tmpVar . ' = [' . $capture . ']('
'php::ClosureFn ' . $tmpVar . ' = []('
. 'INTERNAL_FUNCTION_PARAMETERS, '
. self::TYPE_OBJECT . ' &this_, '
. self::TYPE_ARGS . ' &vars_) ' .
'-> ' . self::TYPE_VAR . ' {' . PHP_EOL;
$oriContext = $this->context;
if ($useCurrentScope) {
$oriBeforeStmtLines = $oriContext->beforeStmtLines;
$oriAfterStmtLines = $oriContext->afterStmtLines;
} else {
$this->context = new FunctionContext();
}
$this->context = new FunctionContext();
$this->context->inClosure = true;
$this->indentLevel++;
@ -83,14 +79,8 @@ trait ClosureGenerator
}
if ($useItem->byRef) {
// 闭包的 use 语法,若为引用类型,可以就地创建变量
if ($useCurrentScope) {
if (!$this->hasVar($var)) {
$this->addLocalVar($var, self::TYPE_REF);
}
} else {
if (!isset($oriContext->localVars[$var])) {
$oriContext->localVars[$var] = self::TYPE_REF;
}
if (!isset($oriContext->localVars[$var])) {
$oriContext->localVars[$var] = self::TYPE_REF;
}
$useVars[] = $this->convertToRef($useItem->var);
} else {
@ -103,10 +93,6 @@ trait ClosureGenerator
}
$this->context = $oriContext;
if ($useCurrentScope) {
$this->context->beforeStmtLines = $oriBeforeStmtLines;
$this->context->afterStmtLines = $oriAfterStmtLines;
}
$this->context->beforeStmtLines[] = $code;
if ($this->methodDef) {

Loading…
Cancel
Save