1--TEST-- 2Lazy objects: Pre-initialization reference source types are properly handled after initializer exception 3--FILE-- 4<?php 5 6class C { 7 public ?C $a; 8 public ?C $b; 9 public $c; 10 public function __construct() { 11 unset($this->b); 12 throw new \Exception('initializer exception'); 13 } 14} 15 16function test(string $name, object $obj) { 17 $reflector = new ReflectionClass(C::class); 18 19 printf("# %s:\n", $name); 20 21 $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, null); 22 $refA = &$obj->a; 23 $reflector->getProperty('b')->setRawValueWithoutLazyInitialization($obj, null); 24 $refB = &$obj->b; 25 26 var_dump($obj); 27 try { 28 var_dump($obj->c); 29 } catch (\Exception $e) { 30 printf("%s: %s\n", $e::class, $e->getMessage()); 31 } 32 var_dump($obj); 33 34 try { 35 // $refA retained its reference source type (except for the proxy 36 // case: it is the responsibility of the initializer to propagate 37 // pre-initialized properties to the instance) 38 $refA = 1; 39 } catch (\Error $e) { 40 printf("%s: %s\n", $e::class, $e->getMessage()); 41 } 42 43 // source type was not duplicated 44 unset($obj->a); 45 $refA = 1; 46 47 try { 48 // $refB retained its reference source type 49 $refB = 1; 50 } catch (\Error $e) { 51 printf("%s: %s\n", $e::class, $e->getMessage()); 52 } 53 54 // source type was not duplicated 55 unset($obj->b); 56 $refB = 1; 57 58} 59 60$reflector = new ReflectionClass(C::class); 61 62$obj = $reflector->newLazyGhost(function ($obj) { 63 var_dump("initializer"); 64 $obj->__construct(); 65}); 66 67test('Ghost', $obj); 68 69$obj = $reflector->newLazyProxy(function ($obj) { 70 var_dump("initializer"); 71 return new C(null); 72}); 73 74test('Proxy', $obj); 75--EXPECTF-- 76# Ghost: 77lazy ghost object(C)#%d (2) { 78 ["a"]=> 79 &NULL 80 ["b"]=> 81 &NULL 82} 83string(11) "initializer" 84Exception: initializer exception 85lazy ghost object(C)#%d (2) { 86 ["a"]=> 87 &NULL 88 ["b"]=> 89 &NULL 90} 91TypeError: Cannot assign int to reference held by property C::$a of type ?C 92TypeError: Cannot assign int to reference held by property C::$b of type ?C 93# Proxy: 94lazy proxy object(C)#%d (2) { 95 ["a"]=> 96 &NULL 97 ["b"]=> 98 &NULL 99} 100string(11) "initializer" 101Exception: initializer exception 102lazy proxy object(C)#%d (2) { 103 ["a"]=> 104 &NULL 105 ["b"]=> 106 &NULL 107} 108TypeError: Cannot assign int to reference held by property C::$a of type ?C 109TypeError: Cannot assign int to reference held by property C::$b of type ?C 110