feat(php): 实现PHP编译器对引用参数的支持

- 修改CompilerBase.php以支持函数引用参数的正确处理
- 添加Reflection::isReferenceArg方法用于检查函数参数是否为引用类型
- 在处理函数调用时针对引用参数创建临时变量并正确传递引用
- 扩展支持对象属性获取作为引用参数的功能
- 添加iterators_006.phpt和iterators_007.phpt测试用例验证迭代器功能
- 添加ref_prop.php示例文件展示引用属性功能
- 重构多个算法示例文件以改进代码结构和可读性
pull/1/head
韩天峰 7 months ago
parent 715abf458d
commit 4ed56de30e
  1. 7
      examples/ref_prop.php
  2. 23
      src/Php/CompilerBase.php
  3. 9
      src/Php/Reflection.php
  4. 85
      tests/core/classes/iterators_006.phpt
  5. 41
      tests/core/classes/iterators_007.phpt

@ -0,0 +1,7 @@
<?php
$o = new StdClass();
$o->a = 1999;
parse_str("c=2000", $o->a);
$prop = $o->a;
$prop = 111;
var_dump($o->a);

@ -1402,17 +1402,20 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$this->hasVar($name)) { if (!$this->hasVar($name)) {
$this->addLocalVar($name, self::TYPE_REF); $this->addLocalVar($name, self::TYPE_REF);
$this->beforeStmtLines[] = $name . ' = php::newReference();'; $this->beforeStmtLines[] = $name . ' = php::newReference();';
} elseif (!$nativeFunction and $funcName) { } elseif (!$nativeFunction and $funcName and Reflection::isReferenceArg($funcName, $i)) {
$funcArg = Reflection::getFunctionParameter($funcName, $i);
// 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数 // 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数
if ($funcArg and $funcArg->isPassedByReference()) { $tmpVar = $this->genTmpVarName();
$tmpVar = $this->genTmpVarName(); $this->addLocalVar($tmpVar, self::TYPE_REF);
$this->addLocalVar($tmpVar, self::TYPE_REF); $this->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();';
$this->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();'; $this->afterStmtLines[] = $name . ' = *' . $tmpVar . ';';
$this->afterStmtLines[] = $name . ' = *' . $tmpVar . ';'; $list_args[] = $tmpVar;
$list_args[] = $tmpVar; continue;
continue; }
} } elseif ($this->isPropertyFetch($arg->value)) {
if (!$nativeFunction and $funcName and Reflection::isReferenceArg($funcName, $i)) {
$obj = $this->parseIdentifier($arg->value->var);
$list_args[] = $obj . '.getPropertyReference(' . $this->identifierToStr($arg->value->name) . ')';
continue;
} }
} }
// 不支持变长参数展开的语法,例如:array_merge(...$arr) // 不支持变长参数展开的语法,例如:array_merge(...$arr)

@ -52,4 +52,13 @@ class Reflection
} }
return $args[$index]; return $args[$index];
} }
public static function isReferenceArg(string $fn, int $index): ?string
{
$param = self::getFunctionParameter($fn, $index);
if (!$param) {
return null;
}
return $param->isPassedByReference() ? $param->getName() : null;
}
} }

@ -0,0 +1,85 @@
--TEST--
ZE2 iterators and array wrapping
--FILE--
<?php
class ai implements Iterator {
private $array;
private $key;
private $current;
function __construct() {
$this->array = array('foo', 'bar', 'baz');
}
function rewind(): void {
reset($this->array);
$this->next();
}
function valid(): bool {
return $this->key !== NULL;
}
function key(): mixed {
return $this->key;
}
function current(): mixed {
return $this->current;
}
function next(): void {
$this->key = key($this->array);
$this->current = current($this->array);
next($this->array);
}
}
class a implements IteratorAggregate {
public function getIterator(): Traversable {
return new ai();
}
}
function main() {
$array = new a();
foreach ($array as $property => $value) {
print "$property: $value\n";
}
#$array = $array->getIterator();
#$array->rewind();
#$array->valid();
#var_dump($array->key());
#var_dump($array->current());
echo "===2nd===\n";
$array = new ai();
foreach ($array as $property => $value) {
print "$property: $value\n";
}
echo "===3rd===\n";
foreach ($array as $property => $value) {
print "$property: $value\n";
}
}
?>
--EXPECT--
0: foo
1: bar
2: baz
===2nd===
0: foo
1: bar
2: baz
===3rd===
0: foo
1: bar
2: baz

@ -0,0 +1,41 @@
--TEST--
ZE2 iterators and exceptions
--FILE--
<?php
class Test implements Iterator
{
public $arr = array(1, 2, 3);
public $x = 0;
public function rewind(): void { if ($this->x == 0) throw new Exception(__METHOD__); reset($this->arr); }
public function current(): mixed { if ($this->x == 1) throw new Exception(__METHOD__); return current($this->arr); }
public function key(): mixed { if ($this->x == 2) throw new Exception(__METHOD__); return key($this->arr); }
public function next(): void { if ($this->x == 3) throw new Exception(__METHOD__); next($this->arr); }
public function valid(): bool { if ($this->x == 4) throw new Exception(__METHOD__); return (key($this->arr) !== NULL); }
}
function main() {
$t = new Test();
while($t->x < 5)
{
try
{
foreach($t as $k => $v)
{
echo "Current\n";
}
}
catch(Exception $e)
{
echo "Caught in " . $e->getMessage() . "()\n";
}
$t->x++;
}
}
?>
--EXPECT--
Caught in Test::rewind()
Caught in Test::current()
Caught in Test::key()
Current
Caught in Test::next()
Caught in Test::valid()
Loading…
Cancel
Save