feat(php): 添加对 foreach 引用语法的支持

- 实现了foreach按引用遍历功能支持
- 添加了类继承链中的原生类检查
- 增加了foreach引用语法的变量类型验证
- 添加了新的测试用例验证引用功能
- 修复了循环引用中的类型安全问题
pull/1/head
韩天峰 5 months ago
parent 6a48de1321
commit a50e889751
  1. 27
      src/Php/CompilerBase.php
  2. 22
      tests/aot/foreach-ref.phpt

@ -1606,6 +1606,10 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$classDef->extends) {
return false;
}
if (!$this->hasNativeClass($classDef->extends)) {
$this->climate->error('Class `' . $classDef->extends . '` is not defined');
return false;
}
$classDef = $this->getClassDef($classDef->extends);
} else {
$methodDef = $classDef->methods[$method];
@ -3058,6 +3062,10 @@ class CompilerBase extends \PhpAot\Core\Translator
$code .= $this->getIndent() . ' ' . $keyVar . ' = iter.key();' . PHP_EOL;
}
if ($node->byRef and !$this->isVarExpr($node->valueVar)) {
$this->fatalError($node, 'Foreach by reference only supports variable as value');
}
if ($node->valueVar->getType() == self::EXPR_ARRAY_DIM_FETCH) {
$array = $this->parseIdentifier($node->valueVar->var);
if (!$this->hasVar($array) or $node->valueVar->dim === null) {
@ -3067,8 +3075,17 @@ class CompilerBase extends \PhpAot\Core\Translator
$code .= $this->getIndent() . "{$array}.offsetSet({$dim}, iter.value());";
} else {
$valueVar = $this->parseIdentifier($node->valueVar);
$this->checkVar($node, $valueVar);
$code .= $this->getIndent() . ' ' . $valueVar . ' = iter.value();' . PHP_EOL;
if ($node->byRef) {
if (!$this->hasVar($valueVar)) {
$this->addLocalVar($valueVar, self::TYPE_REF);
} else if ($this->getVarType($valueVar) !== self::TYPE_REF) {
$this->fatalError($node, 'Cannot assign value to reference of type');
}
$code .= $this->getIndent() . ' ' . $valueVar . ' = iter.valueRef();' . PHP_EOL;
} else {
$this->checkVar($node, $valueVar);
$code .= $this->getIndent() . ' ' . $valueVar . ' = iter.value();' . PHP_EOL;
}
}
$body = $this->parseStmts($node->stmts);
@ -3084,14 +3101,14 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseForeach(Foreach_ $node): string
{
if ($node->byRef) {
$this->fatalError($node, 'Cannot use & with foreach');
}
if ($this->isVarExpr($node->expr)) {
$name = $this->parseIdentifier($node->expr);
if ($this->hasVar($name)) {
$type = $this->getVarType($name);
if ($type === self::TYPE_OBJECT) {
if ($node->byRef) {
$this->fatalError($node, 'Cannot use & with foreach');
}
return $this->parseForeachObject($node);
}
}

@ -0,0 +1,22 @@
--TEST--
foreach statement
--FILE--
<?php
function main()
{
$arr = range(0, 5);
foreach ($arr as &$_v) {
$_v += 5;
}
echo json_encode($arr, JSON_PRETTY_PRINT), "\n";
}
?>
--EXPECT--
[
5,
6,
7,
8,
9,
10
]
Loading…
Cancel
Save