From 989939bb90dfd272e73dbc74ddac94fa6d6d728d Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Sat, 28 Feb 2026 14:04:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(aot):=20=E6=94=AF=E6=8C=81PHP=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E5=B1=95=E5=BC=80=E8=AF=AD=E6=B3=95=E5=92=8C=E5=A4=8D?= =?UTF-8?q?=E6=9D=82=E6=95=B0=E7=BB=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现了数组展开运算符(...)的解析支持 - 添加了混杂数组赋值的多行插入处理逻辑 - 支持动态键名和不同类型的键值组合 - 优化了数组解析的类型判断和内存管理 - 新增了三个数组相关功能测试用例 - 提取了函数参数默认值解析的公共方法 - 修复了类属性默认值null判断的问题 --- src/Php/CompilerBase.php | 92 +++++++++++++++++++++++++++++++++------- src/Php/Translator.php | 3 +- tests/aot/array_001.phpt | 16 +++++++ tests/aot/array_002.phpt | 23 ++++++++++ tests/aot/array_003.phpt | 14 ++++++ 5 files changed, 130 insertions(+), 18 deletions(-) create mode 100644 tests/aot/array_001.phpt create mode 100644 tests/aot/array_002.phpt create mode 100644 tests/aot/array_003.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 4f2980a0..2ff5fdbf 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -891,6 +891,21 @@ class CompilerBase extends \PhpAot\Core\Translator } } + protected function parseParamDefaultValue(?NodeAbstract $default): ?string + { + if (!$default) { + return null; + } + /** + * 函数参数默认值只能为字面量,无法使用表达式获取值 + */ + if ($default instanceof Node\Expr\ConstFetch) { + return $this->parseConstFetch($default, true); + } else { + return $this->parseIdentifier($default); + } + } + protected function parseParams($params, FunctionDef $functionDef): void { $list = []; @@ -908,7 +923,7 @@ class CompilerBase extends \PhpAot\Core\Translator $this->fatalError($param, 'Promoted properties are not supported'); } $name = $this->parseIdentifier($param->var); - $propertyDef = new PropertyDef($name, $param->flags, $param->type, $param->default); + $propertyDef = new PropertyDef($name, $param->flags, $param->type, $this->parseParamDefaultValue($param->default)); $this->classDef->properties[$name] = $propertyDef; } if ($param->variadic and $i !== $last) { @@ -929,14 +944,7 @@ class CompilerBase extends \PhpAot\Core\Translator $argInfo->property = $param->isPromoted(); if (isset($param->default)) { $functionDef->argCountRequired = count($list) - 1; - /** - * 函数参数默认值只能为字面量,无法使用表达式获取值 - */ - if ($param->default instanceof Node\Expr\ConstFetch) { - $argInfo->default = $this->parseConstFetch($param->default, true); - } else { - $argInfo->default = $this->parseIdentifier($param->default); - } + $argInfo->default = $this->parseParamDefaultValue($param->default); } $functionDef->argInfoList[] = $argInfo; } @@ -1526,7 +1534,39 @@ class CompilerBase extends \PhpAot\Core\Translator return self::TYPE_VAR; } - protected function parseArray($node): string + /** + * 混杂数组赋值,需要拆分为多行插入 + */ + private function parseArrayMixed(Node\Expr\Array_ $node): string + { + $tmpVar = $this->genTmpVarName(); + $this->addLocalVar($tmpVar, self::TYPE_ARRAY); + + $items = $node->items; + foreach ($items as $item) { + $value = $this->parseIdentifier($item->value); + if ($item->unpack) { + $this->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.merge(' . $value . ');'; + } elseif ($item->key) { + $key = $this->parseIdentifier($item->key); + if (str_starts_with($key, self::LITERAL_STRINGS)) { + $key = "{$key}.toStdString()"; + } elseif ($key === '0L') { + $key = 'php::zero'; + } + $this->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.set(' . $key . ', ' . $value . ');'; + } else { + $this->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.append(' . $value . ');'; + } + } + + // 释放临时变量,避免修改数组产生数组复制操作 + $this->afterStmtLines[] = $this->getIndent() . $tmpVar . '.unset();'; + + return $tmpVar; + } + + protected function parseArray(Node\Expr\Array_ $node): string { $items = $node->items; // 优化代码风格,空数组直接返回{},否则会产生一些空洞内容 @@ -1534,21 +1574,41 @@ class CompilerBase extends \PhpAot\Core\Translator return self::TYPE_ARRAY . '{}'; } - $assocArray = false; + $hasKey = false; + $hasIntKey = false; + $hasStrKey = false; + $hasUnpack = false; + $hasVarKey = false; + $hasNextInsert = false; foreach ($items as $item) { + if ($item->unpack) { + $hasUnpack = true; + } if ($item->key) { - $assocArray = true; - break; + if ($item->key instanceof Node\Scalar\LNumber) { + $hasIntKey = true; + } elseif ($item->key instanceof Node\Scalar\String_) { + $hasStrKey = true; + } else { + $hasVarKey = true; + } + $hasKey = true; + } else { + $hasNextInsert = true; } } + // 存在混合键,则需要拆分为多行插入 + if ($hasUnpack or $hasVarKey or ($hasNextInsert && $hasKey) or ($hasIntKey and $hasStrKey)) { + return $this->parseArrayMixed($node); + } + $list = []; $this->indentLevel++; foreach ($items as $item) { $value = $this->parseIdentifier($item->value); - if ($assocArray) { - // TODO 混杂模式数组赋值 - $key = $item->key ? $this->parseIdentifier($item->key) : self::VALUE_NULL; + if ($item->key) { + $key = $this->parseIdentifier($item->key); if (str_starts_with($key, self::LITERAL_STRINGS)) { $key = "{$key}.toStdString()"; } elseif ($key === '0L') { diff --git a/src/Php/Translator.php b/src/Php/Translator.php index d53dd988..37830e62 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -881,10 +881,9 @@ class Translator extends Preprocessor protected function genClassProperty(PropertyDef $prop): string { $code = $prop->type . ' ' . $prop->name; - if ($prop->default) { + if ($prop->default !== null) { $code .= ' = ' . $prop->default; } - return $code . ';' . PHP_EOL; } diff --git a/tests/aot/array_001.phpt b/tests/aot/array_001.phpt new file mode 100644 index 00000000..2317b603 --- /dev/null +++ b/tests/aot/array_001.phpt @@ -0,0 +1,16 @@ +--TEST-- +Array 001 +--FILE-- + 'foo', + 1000 => 'bar', +]; +var_dump(count($array2)); +?> +--EXPECT-- +int(3) +int(2) \ No newline at end of file diff --git a/tests/aot/array_002.phpt b/tests/aot/array_002.phpt new file mode 100644 index 00000000..707c8642 --- /dev/null +++ b/tests/aot/array_002.phpt @@ -0,0 +1,23 @@ +--TEST-- +Array 002 +--FILE-- + +--EXPECT-- +array(6) { + [0]=> + int(2) + [1]=> + int(5) + [2]=> + int(1) + [3]=> + int(3) + [4]=> + int(4) + [5]=> + int(6) +} diff --git a/tests/aot/array_003.phpt b/tests/aot/array_003.phpt new file mode 100644 index 00000000..070c22cc --- /dev/null +++ b/tests/aot/array_003.phpt @@ -0,0 +1,14 @@ +--TEST-- +Array 003 +--FILE-- + 'foo', + 1000 => 'bar', +]; +var_dump(count($array2)); +?> +--EXPECT-- +int(2) \ No newline at end of file