From 4ed56de30e7efbc97d5f31c5dff8c2123f331c1f Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Fri, 16 Jan 2026 14:53:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E5=AE=9E=E7=8E=B0PHP=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E5=99=A8=E5=AF=B9=E5=BC=95=E7=94=A8=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改CompilerBase.php以支持函数引用参数的正确处理 - 添加Reflection::isReferenceArg方法用于检查函数参数是否为引用类型 - 在处理函数调用时针对引用参数创建临时变量并正确传递引用 - 扩展支持对象属性获取作为引用参数的功能 - 添加iterators_006.phpt和iterators_007.phpt测试用例验证迭代器功能 - 添加ref_prop.php示例文件展示引用属性功能 - 重构多个算法示例文件以改进代码结构和可读性 --- examples/ref_prop.php | 7 +++ src/Php/CompilerBase.php | 23 ++++---- src/Php/Reflection.php | 9 +++ tests/core/classes/iterators_006.phpt | 85 +++++++++++++++++++++++++++ tests/core/classes/iterators_007.phpt | 41 +++++++++++++ 5 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 examples/ref_prop.php create mode 100644 tests/core/classes/iterators_006.phpt create mode 100644 tests/core/classes/iterators_007.phpt diff --git a/examples/ref_prop.php b/examples/ref_prop.php new file mode 100644 index 00000000..e4701cb8 --- /dev/null +++ b/examples/ref_prop.php @@ -0,0 +1,7 @@ +a = 1999; +parse_str("c=2000", $o->a); +$prop = $o->a; +$prop = 111; +var_dump($o->a); diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 7df51191..89103e9c 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1402,17 +1402,20 @@ class CompilerBase extends \PhpAot\Core\Translator if (!$this->hasVar($name)) { $this->addLocalVar($name, self::TYPE_REF); $this->beforeStmtLines[] = $name . ' = php::newReference();'; - } elseif (!$nativeFunction and $funcName) { - $funcArg = Reflection::getFunctionParameter($funcName, $i); + } elseif (!$nativeFunction and $funcName and Reflection::isReferenceArg($funcName, $i)) { // 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数 - if ($funcArg and $funcArg->isPassedByReference()) { - $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_REF); - $this->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();'; - $this->afterStmtLines[] = $name . ' = *' . $tmpVar . ';'; - $list_args[] = $tmpVar; - continue; - } + $tmpVar = $this->genTmpVarName(); + $this->addLocalVar($tmpVar, self::TYPE_REF); + $this->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();'; + $this->afterStmtLines[] = $name . ' = *' . $tmpVar . ';'; + $list_args[] = $tmpVar; + 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) diff --git a/src/Php/Reflection.php b/src/Php/Reflection.php index 33c71eff..33bacb9e 100644 --- a/src/Php/Reflection.php +++ b/src/Php/Reflection.php @@ -52,4 +52,13 @@ class Reflection } 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; + } } diff --git a/tests/core/classes/iterators_006.phpt b/tests/core/classes/iterators_006.phpt new file mode 100644 index 00000000..1cb34097 --- /dev/null +++ b/tests/core/classes/iterators_006.phpt @@ -0,0 +1,85 @@ +--TEST-- +ZE2 iterators and array wrapping +--FILE-- +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 diff --git a/tests/core/classes/iterators_007.phpt b/tests/core/classes/iterators_007.phpt new file mode 100644 index 00000000..5c4a8e35 --- /dev/null +++ b/tests/core/classes/iterators_007.phpt @@ -0,0 +1,41 @@ +--TEST-- +ZE2 iterators and exceptions +--FILE-- +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()