feat(php): 添加类型对象重新赋值检查功能

- 在对象赋值时检测类型冲突并抛出错误
- 实现 typed object 的类型安全检查机制
- 添加 Cannot re-assign typed object 错误提示
- 扩展 AssignTest 测试用例验证类型重分配行为
- 优化变量类型检查逻辑确保类型一致性
pull/1/head
韩天峰 5 months ago
parent a1c922dac2
commit 9f52d48770
  1. 7
      phpunit/code/re-assign-2.php
  2. 5
      phpunit/src/AssignTest.php
  3. 30
      src/Php/CompilerBase.php

@ -0,0 +1,7 @@
<?php
function main()
{
$obj1 = new stdClass();
$obj2 = new ArrayObject();
$obj1 = $obj2;
}

@ -6,4 +6,9 @@ class AssignTest extends \BaseTest
{ {
$this->exec('Cannot re-assign variable', 're-assign.php'); $this->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');
}
} }

@ -1333,12 +1333,22 @@ class CompilerBase extends \PhpAot\Core\Translator
// 类型推断,获取对象的类名 // 类型推断,获取对象的类名
if ($this->isNewExpr($right) and $this->isNameExpr($right->class)) { if ($this->isNewExpr($right) and $this->isNameExpr($right->class)) {
$class = $this->parseIdentifier($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; $type = self::TYPE_OBJECT;
} elseif ($this->isFuncCallExpr($right) and $this->isNameExpr($right->name)) { } elseif ($this->isFuncCallExpr($right) and $this->isNameExpr($right->name)) {
$fn = $this->parseIdentifier($right->name); $fn = $this->parseIdentifier($right->name);
if (count($right->args) === 2 and $fn === 'objval' and $this->isScalarString($right->args[1]->value)) { 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; $type = self::TYPE_OBJECT;
} elseif (count($right->args) === 1 and $fn === 'any') { } elseif (count($right->args) === 1 and $fn === 'any') {
$type = self::TYPE_VAR; $type = self::TYPE_VAR;
@ -1370,16 +1380,22 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
} elseif ($this->isVarExpr($right)) { } elseif ($this->isVarExpr($right)) {
$rightVar = $this->parseIdentifier($right); $rightVar = $this->parseIdentifier($right);
if ($this->hasVar($rightVar) and $this->isTypedObject($rightVar)) { $type = $this->getVarType($rightVar);
$type = self::TYPE_OBJECT; if ($this->isTypedObject($rightVar) and $this->isTypedObject($var)) {
$this->addObject($var, $this->getObjectType($rightVar)); $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)) { if (!$this->hasVar($var)) {
$this->addLocalVar($var, $type); $this->addLocalVar($var, $type);
} else if ($this->getVarType($var) != $type) { } else {
$this->fatalError($left, "Cannot re-assign variable `\${$var}` from " . $this->getVarType($var) . " to " . $type); 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')) { } elseif ($this->isPropertyFetch($left) and !$left->getAttribute('nativeProperty')) {
return $this->parseAssignPropertyFetch($left, $right); return $this->parseAssignPropertyFetch($left, $right);

Loading…
Cancel
Save