1--TEST-- 2A SensitiveParameterValue keeps inner objects alive. 3--FILE-- 4<?php 5 6class CustomDestructor 7{ 8 public function __construct(private int $id) 9 { 10 echo __METHOD__, " - ", $this->id, PHP_EOL; 11 } 12 13 public function __destruct() 14 { 15 echo __METHOD__, " - ", $this->id, PHP_EOL; 16 } 17 18 public function getId(): int 19 { 20 return $this->id; 21 } 22} 23 24function test(#[SensitiveParameter] CustomDestructor $o, bool $throw) 25{ 26 if ($throw) { 27 throw new Exception('Error'); 28 } 29} 30 31function wrapper(int $id, bool $throw) 32{ 33 $o = new CustomDestructor($id); 34 test($o, $throw); 35} 36 37function main(): SensitiveParameterValue 38{ 39 try { 40 echo "Before 1", PHP_EOL; 41 wrapper(1, false); 42 echo "After 1", PHP_EOL; 43 echo "Before 2", PHP_EOL; 44 wrapper(2, true); 45 echo "Not Reached: After 2", PHP_EOL; 46 } catch (Exception $e) { 47 echo "catch", PHP_EOL; 48 return $e->getTrace()[0]['args'][0]; 49 } 50} 51 52$v = main(); 53 54var_dump($v->getValue()->getId()); 55 56echo "Before unset", PHP_EOL; 57 58unset($v); 59 60echo "After unset", PHP_EOL; 61 62?> 63--EXPECT-- 64Before 1 65CustomDestructor::__construct - 1 66CustomDestructor::__destruct - 1 67After 1 68Before 2 69CustomDestructor::__construct - 2 70catch 71int(2) 72Before unset 73CustomDestructor::__destruct - 2 74After unset 75