diff --git a/src/Parser/BinaryOpTrait.php b/src/Parser/BinaryOpTrait.php index 9ee83534..a6722e0f 100644 --- a/src/Parser/BinaryOpTrait.php +++ b/src/Parser/BinaryOpTrait.php @@ -535,6 +535,13 @@ trait BinaryOpTrait $tmpVar = $this->addTmpVar($type); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $value . ';'; $this->appendCapturedStmtLinesToContext($afterStmts); + if ($type === Type::VAR) { + // The declaration is function-scoped, but PHP releases an owned + // expression temporary after the statement that consumes it. + // Keeping the value here would extend object lifetimes (notably + // WeakReference targets) until the native function returns. + $this->context->afterStmtLines[] = $tmpVar . '.unset();'; + } return $tmpVar; } diff --git a/tests/compiler/basic/weak-reference-expression-lifetime.phpt b/tests/compiler/basic/weak-reference-expression-lifetime.phpt new file mode 100644 index 00000000..a8d28a06 --- /dev/null +++ b/tests/compiler/basic/weak-reference-expression-lifetime.phpt @@ -0,0 +1,42 @@ +--TEST-- +Expression temporaries release owned objects at the end of the PHP statement +--FILE-- +get() === $target; + unset($target); + gc_collect_cycles(); + + var_dump($liveIdentity); + var_dump($weak->get() === null); + + $different = make_temporary_probe() === new stdClass(); + var_dump($different); + var_dump(TemporaryLifetimeProbe::$destroyed); +} + +?> +--EXPECT-- +bool(true) +bool(true) +bool(false) +int(1)