feat(aot): 支持PHP数组展开语法和复杂数组解析

- 实现了数组展开运算符(...)的解析支持
- 添加了混杂数组赋值的多行插入处理逻辑
- 支持动态键名和不同类型的键值组合
- 优化了数组解析的类型判断和内存管理
- 新增了三个数组相关功能测试用例
- 提取了函数参数默认值解析的公共方法
- 修复了类属性默认值null判断的问题
pull/1/head
韩天峰 6 months ago
parent 34f157871d
commit 989939bb90
  1. 92
      src/Php/CompilerBase.php
  2. 3
      src/Php/Translator.php
  3. 16
      tests/aot/array_001.phpt
  4. 23
      tests/aot/array_002.phpt
  5. 14
      tests/aot/array_003.phpt

@ -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 protected function parseParams($params, FunctionDef $functionDef): void
{ {
$list = []; $list = [];
@ -908,7 +923,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->fatalError($param, 'Promoted properties are not supported'); $this->fatalError($param, 'Promoted properties are not supported');
} }
$name = $this->parseIdentifier($param->var); $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; $this->classDef->properties[$name] = $propertyDef;
} }
if ($param->variadic and $i !== $last) { if ($param->variadic and $i !== $last) {
@ -929,14 +944,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$argInfo->property = $param->isPromoted(); $argInfo->property = $param->isPromoted();
if (isset($param->default)) { if (isset($param->default)) {
$functionDef->argCountRequired = count($list) - 1; $functionDef->argCountRequired = count($list) - 1;
/** $argInfo->default = $this->parseParamDefaultValue($param->default);
* 函数参数默认值只能为字面量,无法使用表达式获取值
*/
if ($param->default instanceof Node\Expr\ConstFetch) {
$argInfo->default = $this->parseConstFetch($param->default, true);
} else {
$argInfo->default = $this->parseIdentifier($param->default);
}
} }
$functionDef->argInfoList[] = $argInfo; $functionDef->argInfoList[] = $argInfo;
} }
@ -1526,7 +1534,39 @@ class CompilerBase extends \PhpAot\Core\Translator
return self::TYPE_VAR; 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; $items = $node->items;
// 优化代码风格,空数组直接返回{},否则会产生一些空洞内容 // 优化代码风格,空数组直接返回{},否则会产生一些空洞内容
@ -1534,21 +1574,41 @@ class CompilerBase extends \PhpAot\Core\Translator
return self::TYPE_ARRAY . '{}'; return self::TYPE_ARRAY . '{}';
} }
$assocArray = false; $hasKey = false;
$hasIntKey = false;
$hasStrKey = false;
$hasUnpack = false;
$hasVarKey = false;
$hasNextInsert = false;
foreach ($items as $item) { foreach ($items as $item) {
if ($item->unpack) {
$hasUnpack = true;
}
if ($item->key) { if ($item->key) {
$assocArray = true; if ($item->key instanceof Node\Scalar\LNumber) {
break; $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 = []; $list = [];
$this->indentLevel++; $this->indentLevel++;
foreach ($items as $item) { foreach ($items as $item) {
$value = $this->parseIdentifier($item->value); $value = $this->parseIdentifier($item->value);
if ($assocArray) { if ($item->key) {
// TODO 混杂模式数组赋值 $key = $this->parseIdentifier($item->key);
$key = $item->key ? $this->parseIdentifier($item->key) : self::VALUE_NULL;
if (str_starts_with($key, self::LITERAL_STRINGS)) { if (str_starts_with($key, self::LITERAL_STRINGS)) {
$key = "{$key}.toStdString()"; $key = "{$key}.toStdString()";
} elseif ($key === '0L') { } elseif ($key === '0L') {

@ -881,10 +881,9 @@ class Translator extends Preprocessor
protected function genClassProperty(PropertyDef $prop): string protected function genClassProperty(PropertyDef $prop): string
{ {
$code = $prop->type . ' ' . $prop->name; $code = $prop->type . ' ' . $prop->name;
if ($prop->default) { if ($prop->default !== null) {
$code .= ' = ' . $prop->default; $code .= ' = ' . $prop->default;
} }
return $code . ';' . PHP_EOL; return $code . ';' . PHP_EOL;
} }

@ -0,0 +1,16 @@
--TEST--
Array 001
--FILE--
<?php
$array1 = [1,2,3];
var_dump(count($array1));
$array2 = [
99 => 'foo',
1000 => 'bar',
];
var_dump(count($array2));
?>
--EXPECT--
int(3)
int(2)

@ -0,0 +1,23 @@
--TEST--
Array 002
--FILE--
<?php
$array1 = [1, 3, 4];
$array2 = [2, 5, ...$array1, 6, ];
var_dump($array2);
?>
--EXPECT--
array(6) {
[0]=>
int(2)
[1]=>
int(5)
[2]=>
int(1)
[3]=>
int(3)
[4]=>
int(4)
[5]=>
int(6)
}

@ -0,0 +1,14 @@
--TEST--
Array 003
--FILE--
<?php
$key = 100;
$array2 = [
$key => 'foo',
1000 => 'bar',
];
var_dump(count($array2));
?>
--EXPECT--
int(2)
Loading…
Cancel
Save