From 9f52d487700a4fef8b7905afe28b7179ec4b727c Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Wed, 1 Apr 2026 18:42:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E6=B7=BB=E5=8A=A0=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=AF=B9=E8=B1=A1=E9=87=8D=E6=96=B0=E8=B5=8B=E5=80=BC?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在对象赋值时检测类型冲突并抛出错误 - 实现 typed object 的类型安全检查机制 - 添加 Cannot re-assign typed object 错误提示 - 扩展 AssignTest 测试用例验证类型重分配行为 - 优化变量类型检查逻辑确保类型一致性 --- phpunit/code/re-assign-2.php | 7 +++++++ phpunit/src/AssignTest.php | 5 +++++ src/Php/CompilerBase.php | 30 +++++++++++++++++++++++------- 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 phpunit/code/re-assign-2.php diff --git a/phpunit/code/re-assign-2.php b/phpunit/code/re-assign-2.php new file mode 100644 index 00000000..d6d8d211 --- /dev/null +++ b/phpunit/code/re-assign-2.php @@ -0,0 +1,7 @@ +exec('Cannot re-assign variable', 're-assign.php'); } + + public function testAssignClass() + { + $this->exec('Cannot re-assign typed object `$obj1` from `stdClass` to `ArrayObject`', 're-assign-2.php'); + } } diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 48f9544b..36598586 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -1333,12 +1333,22 @@ class CompilerBase extends \PhpAot\Core\Translator // 类型推断,获取对象的类名 if ($this->isNewExpr($right) and $this->isNameExpr($right->class)) { $class = $this->parseIdentifier($right->class); - $this->addObject($var, $this->getNamespacedClassName($class)); + $fullClass = $this->getNamespacedClassName($class); + if ($this->isTypedObject($var)) { + $leftClass = $this->getObjectType($var); + $this->fatalError($left, "Cannot re-assign typed object `\${$var}` from `{$leftClass}` to `{$fullClass}`"); + } + $this->addObject($var, $fullClass); $type = self::TYPE_OBJECT; } elseif ($this->isFuncCallExpr($right) and $this->isNameExpr($right->name)) { $fn = $this->parseIdentifier($right->name); if (count($right->args) === 2 and $fn === 'objval' and $this->isScalarString($right->args[1]->value)) { - $this->addObject($var, $this->getNamespacedClassName($this->parseIdentifier($right->args[1]->value))); + $fullClass = $this->getNamespacedClassName($this->parseIdentifier($right->args[1]->value)); + if ($this->isTypedObject($var)) { + $leftClass = $this->getObjectType($var); + $this->fatalError($left, "Cannot re-assign typed object `\${$var}` from `{$leftClass}` to `{$fullClass}`"); + } + $this->addObject($var, $fullClass); $type = self::TYPE_OBJECT; } elseif (count($right->args) === 1 and $fn === 'any') { $type = self::TYPE_VAR; @@ -1370,16 +1380,22 @@ class CompilerBase extends \PhpAot\Core\Translator } } elseif ($this->isVarExpr($right)) { $rightVar = $this->parseIdentifier($right); - if ($this->hasVar($rightVar) and $this->isTypedObject($rightVar)) { - $type = self::TYPE_OBJECT; - $this->addObject($var, $this->getObjectType($rightVar)); + $type = $this->getVarType($rightVar); + if ($this->isTypedObject($rightVar) and $this->isTypedObject($var)) { + $leftClass = $this->getObjectType($var); + $rightClass = $this->getObjectType($rightVar); + $this->fatalError($left, "Cannot re-assign typed object `\${$var}` from `{$leftClass}` to `{$rightClass}`"); } } if (!$this->hasVar($var)) { $this->addLocalVar($var, $type); - } else if ($this->getVarType($var) != $type) { - $this->fatalError($left, "Cannot re-assign variable `\${$var}` from " . $this->getVarType($var) . " to " . $type); + } else { + if ($this->isTypedObject($var) and $type !== self::TYPE_OBJECT or + $this->getVarType($var) === self::TYPE_ARRAY and $type !== self::TYPE_ARRAY + ) { + $this->fatalError($left, "Cannot re-assign variable `\${$var}` from " . $this->getVarType($var) . " to " . $type); + } } } elseif ($this->isPropertyFetch($left) and !$left->getAttribute('nativeProperty')) { return $this->parseAssignPropertyFetch($left, $right);