fix(closure): 修复闭包生成器中的变量捕获逻辑

- 修正 ClosureGenerator.php 中的变量捕获操作符,从值传递改为引用传递
- 更新 ConstantDef 类构造函数以支持数组表达式存储
- 修改模板文件中的类定义检查逻辑,使用 empty 函数替代布尔判断
- 重构类常量生成方法,将 genUpdateClassConstants 重命名为 genClassArrayConstants
- 添加 php_get_create_object_fn 辅助函数以正确获取对象创建函数
- 优化类常量定义解析,支持数组类型的常量表达式处理
pull/1/head
韩天峰 5 months ago
parent 78c7daa646
commit 7989c551bb
  1. 6
      src/Php/Entity/ConstantDef.php
  2. 2
      src/Php/Generator/ClosureGenerator.php
  3. 17
      src/Php/Translator.php
  4. 4
      src/cpp/php_aot_helper.h
  5. 6
      src/template/extension.cc.php

@ -8,18 +8,22 @@
namespace PhpAot\Php\Entity;
use PhpParser\Node\Expr;
class ConstantDef
{
public string $name;
public string $type;
public string $flags;
public string $value;
public string $arrayExpr;
public function __construct(string $name, string $flags, string $type, string $value)
public function __construct(string $name, string $flags, string $type, string $value, string $arrayExpr = '')
{
$this->name = $name;
$this->type = $type;
$this->flags = $flags;
$this->value = $value;
$this->arrayExpr = $arrayExpr;
}
}

@ -29,7 +29,7 @@ trait ClosureGenerator
$tmpVar = $this->genTmpVarName();
// 必须使用 = 捕获,不能使用 & ,否则可能会出现悬空指针
// 在 PHP 中 = 赋值是浅拷贝,仅增加一次引用计数,和 zval (16 字节) 封装的赋值
$capture = $useCurrentScope ? '=' : '';
$capture = $useCurrentScope ? '&' : '';
$code = $this->getIndent() .
'php::ClosureFn ' . $tmpVar . ' = [' . $capture . ']('

@ -419,6 +419,7 @@ class Translator extends Preprocessor
{
$code = '#include <phpx.h>' . PHP_EOL;
// 函数的默认值可能会使用字符串字面量,需要提前声明
$literalStringsCount = count($this->literalStrings);
$code .= 'extern ' . self::TYPE_STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL;
@ -526,14 +527,17 @@ class Translator extends Preprocessor
return $scanner->scan();
}
protected function genUpdateClassConstants(): string
protected function genClassArrayConstants(): string
{
$code = '';
foreach ($this->classes as $classDef) {
foreach ($classDef->constants as $constant) {
if ($constant->type === self::TYPE_ARRAY) {
$constName = self::PREFIX . $this->getNativeName($constant->name, $classDef->namespace, $classDef->name);
$code .= "do {\n";
$code .= $constant->arrayExpr;
$code .= $constName . " = " . $constant->value . ";\n";
$code .= "} while(0);\n";
}
}
}
@ -1061,6 +1065,7 @@ class Translator extends Preprocessor
protected function parseClassConstDef(Node\Stmt\ClassConst $v): void
{
$this->resetFunction();
$flags = $v->flags;
if ($v->type) {
$type = $this->parseTypeDecl($v->type, self::DECL_TYPE_OF_CONST);
@ -1076,7 +1081,15 @@ class Translator extends Preprocessor
};
}
$constName = $this->parseIdentifier($const->name);
$constInfo = new ConstantDef($constName, $flags, $type, $this->parseIdentifier($const->value));
$constValue = $this->parseIdentifier($const->value);
$arrayExpr = '';
if ($this->context->beforeStmtLines) {
if ($this->context->localVars) {
$arrayExpr .= $this->genLocalVarDecl();
}
$arrayExpr .= $this->parseBeforeStmtLines();
}
$constInfo = new ConstantDef($constName, $flags, $type, $constValue, $arrayExpr);
$this->classDef->constants[$constInfo->name] = $constInfo;
}
}

@ -19,3 +19,7 @@ extern const char *php_get_called_class(php::Object &this_);
extern zend_class_entry *php_get_called_ce(php::Object &this_);
extern php::Scope php_switch_scope(php::Object &this_);
extern void php_restore_scope(php::Scope &ori_scope);
static inline auto php_get_create_object_fn(zend_class_entry *ce) {
return ce->create_object ? ce->create_object : zend_objects_new;
}

@ -123,10 +123,10 @@ foreach ($this->classCeList as $ce):
?>
<?=$ce?> = <?= $info['func'] ?>(<?= $info['args'] ?>);
<?php
if ($info['classDef'] and $info['classDef']->requireCtor):
if (!empty($info['classDef']) and $info['classDef']->requireCtor):
$className = $info['classDef']->getNamespacedName();
?>
create_object_<?=$className?> = <?=$ce?>->create_object ? create_object_<?=$className?> : zend_objects_new;
create_object_<?=$className?> = php_get_create_object_fn(<?=$ce?>);
<?=$ce?>->create_object = [](zend_class_entry *class_type) -> zend_object* {
auto obj = create_object_<?= $className ?>(class_type);
<?php foreach ($info['classDef']->properties as $property):
@ -178,7 +178,7 @@ endforeach;
?>
// class array constants
<?=$this->genUpdateClassConstants();?>
<?=$this->genClassArrayConstants();?>
}
void php_app_clean() {

Loading…
Cancel
Save