diff --git a/src/Parser/AssignOpTrait.php b/src/Parser/AssignOpTrait.php index cf826761..826cd011 100644 --- a/src/Parser/AssignOpTrait.php +++ b/src/Parser/AssignOpTrait.php @@ -862,6 +862,17 @@ trait AssignOpTrait protected function parseAssignOpCoalesce(Expr\AssignOp\Coalesce $expr): string { $this->checkLeftValue($expr->var); + + // PHP 允许对未定义的简单变量使用 ??=(例如 `$a ??= 123`): + // 此时 isset 为 false,直接执行赋值。需要提前声明该局部变量, + // 否则 isset 检查会因变量未定义而报错。此处必须声明为 Type::VAR + // (Variant),使其初值为 NULL,从而 isset 在运行时正确判定为 + // false 并执行赋值;若使用原生类型,isset 恒为 true 会导致取到 + // 未初始化的默认值(如 int(0)、空字符串)。 + if ($this->isVarExpr($expr->var) and !$this->hasVar($this->parseIdentifier($expr->var))) { + $this->addLocalVar($this->parseIdentifier($expr->var), Type::VAR); + } + $isset = $this->parseChainedExpr($expr->var, self::OP_ISSET); $var = $this->parseWritableIdentifier($expr->var); @@ -878,9 +889,6 @@ trait AssignOpTrait if ($this->isVarExpr($expr->expr) and !$this->hasVar($right)) { $this->errorUndefinedVariable($expr->expr); } - if ($this->isVarExpr($expr->var) and !$this->hasVar($var)) { - $this->addLocalVar($var, $this->getNormalAssignType($this->detectTypeOfExpr($expr->expr))); - } return '(' . $isset . '?' . $var . ':(' . $var . ' = ' . $right . '))'; } diff --git a/tests/compiler/coalesce/assign-coalesce-undefined-var.phpt b/tests/compiler/coalesce/assign-coalesce-undefined-var.phpt new file mode 100644 index 00000000..4aad8edb --- /dev/null +++ b/tests/compiler/coalesce/assign-coalesce-undefined-var.phpt @@ -0,0 +1,14 @@ +--TEST-- +assign coalesce on undefined variable +--FILE-- + +--EXPECT-- +int(123) +string(3) "foo"