From 254e1607b5985feaaf7ee706ff98c2f6a4fb8289 Mon Sep 17 00:00:00 2001 From: Yurun Date: Tue, 7 Jul 2026 16:18:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(compiler):=20=E4=BF=AE=E5=A4=8Dunset?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E5=8F=98=E9=87=8F=E5=90=8E=E5=AF=B9=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E7=9A=84=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Php/CompilerBase.php | 12 ++- tests/aot/coalesce/unset-ref-coalesce.phpt | 96 ++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/aot/coalesce/unset-ref-coalesce.phpt diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 3b3cf0cd..fe160707 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -5087,6 +5087,12 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont $type = $this->getVarType($name); if ($this->isNativeType($type)) { $this->warning($var, "Variable of native type `\${$name}` cannot be unset"); + } elseif ($type === self::TYPE_REF) { + // Reinitialize as a fresh empty Ref so subsequent writes + // to this variable don't access freed memory. + // Do NOT change localVars type — it must stay TYPE_REF + // for foreach-by-ref to work correctly. + $lines[] = $name . ' = ' . self::TYPE_REF . '();'; } else { $lines[] = "{$name}.unset();"; } @@ -5977,7 +5983,11 @@ class CompilerBase extends \PhpAot\Core\Translator implements PropertyAccessCont $fn = $this->getChainedFunc($op); $expr = $node; if ($this->isVarExpr($expr)) { - return $fn . '(' . $this->parseExpr($expr) . ')'; + if (!$getValue) { + return $fn . '(' . $this->parseExpr($expr) . ')'; + } + // $getValue is true: fall through to use the chain+result mechanism, + // which ensures the result type is TYPE_VAR (compatible with ternaries). } // 单属性读取(非链式) if ($this->isPropertyFetch($expr) and $this->isVarExpr($expr->var) and $this->isIdExpr($expr->name)) { diff --git a/tests/aot/coalesce/unset-ref-coalesce.phpt b/tests/aot/coalesce/unset-ref-coalesce.phpt new file mode 100644 index 00000000..40c7ab9f --- /dev/null +++ b/tests/aot/coalesce/unset-ref-coalesce.phpt @@ -0,0 +1,96 @@ +--TEST-- +Null coalescing (??) on unset reference variable +--FILE-- + +--EXPECT-- +int(2) +int(2) +int(2) +bool(false) +int(123) +string(5) "world" +string(5) "world" +string(5) "world" +bool(false) +string(7) "default" +int(42) +string(8) "fallback" +int(30) +int(20) +int(200) +int(300) +int(100) +int(777) +bool(false) +int(-1)