1--TEST-- 2Lazy objects: ReflectionProperty::skipLazyInitialization() prevent properties from triggering initializer 3--FILE-- 4<?php 5 6#[\AllowDynamicProperties] 7class A { 8 private $priv = 'priv A'; 9 private $privA = 'privA'; 10 protected $prot = 'prot'; 11 public $pubA = 'pubA'; 12 13 public static $static = 'static'; 14 15 public $noDefault; 16 public string $noDefaultTyped; 17 public $initialized; 18 19 public $hooked { 20 get { return $this->hooked; } 21 set ($value) { $this->hooked = strtoupper($value); } 22 } 23 24 public $virtual { 25 get { return 'virtual'; } 26 set ($value) { } 27 } 28} 29 30class B extends A { 31 private $priv = 'privB'; 32 public $pubB = 'pubB'; 33 34 private readonly string $readonly; 35} 36 37set_error_handler(function ($errno, $errstr) { 38 throw new Error($errstr); 39}); 40 41function testProperty(callable $makeObj, $propReflector) { 42 43 $reflector = new ReflectionClass(B::class); 44 45 $getValue = function ($obj, $propReflector) { 46 $name = $propReflector->getName(); 47 return $obj->$name; 48 }; 49 50 printf("\n## %s", $propReflector); 51 52 printf("\nskipInitializerForProperty():\n"); 53 $obj = $makeObj(); 54 $skept = false; 55 try { 56 $propReflector->skipLazyInitialization($obj); 57 $skept = true; 58 } catch (ReflectionException $e) { 59 printf("%s: %s\n", $e::class, $e->getMessage()); 60 } 61 if (!$reflector->isUninitializedLazyObject($obj)) { 62 printf("Object was unexpectedly initialized (1)\n"); 63 } 64 if ($skept) { 65 try { 66 printf("getValue(): "); 67 var_dump($getValue($obj, $propReflector)); 68 } catch (\Error $e) { 69 printf("%s: %s\n", $e::class, $e->getMessage()); 70 } 71 if (!$propReflector->isStatic()) { 72 $propReflector->setValue($obj, ''); 73 } 74 if (!$reflector->isUninitializedLazyObject($obj)) { 75 printf("Object was unexpectedly initialized (1)\n"); 76 } 77 } 78 79 printf("\nsetRawValueWithoutLazyInitialization():\n"); 80 $obj = $makeObj(); 81 $skept = false; 82 try { 83 $propReflector->setRawValueWithoutLazyInitialization($obj, 'value'); 84 $skept = true; 85 } catch (ReflectionException $e) { 86 printf("%s: %s\n", $e::class, $e->getMessage()); 87 } 88 if (!$reflector->isUninitializedLazyObject($obj)) { 89 printf("Object was unexpectedly initialized (1)\n"); 90 } 91 if ($skept) { 92 try { 93 printf("getValue(): "); 94 var_dump($getValue($obj, $propReflector)); 95 } catch (\Error $e) { 96 printf("%s: %s\n", $e::class, $e->getMessage()); 97 } 98 if (!$reflector->isUninitializedLazyObject($obj)) { 99 printf("Object was unexpectedly initialized (1)\n"); 100 } 101 } 102} 103 104function test(string $name, callable $makeObj) { 105 printf("# %s:\n", $name); 106 107 $reflector = new ReflectionClass(B::class); 108 109 foreach ($reflector->getProperties() as $propReflector) { 110 testProperty($makeObj, $propReflector); 111 } 112 113 testProperty($makeObj, new class { 114 function getName() { 115 return 'dynamicProp'; 116 } 117 function setValue($obj, $value) { 118 $obj->dynamicProp = $value; 119 } 120 function isStatic() { 121 return false; 122 } 123 // TODO: refactor this test 124 function skipLazyInitialization(object $object) { 125 throw new \ReflectionException(); 126 } 127 function setRawValueWithoutLazyInitialization(object $object) { 128 throw new \ReflectionException(); 129 } 130 function __toString() { 131 return "Property [ \$dynamicProp ]\n"; 132 } 133 }); 134} 135 136$reflector = new ReflectionClass(B::class); 137 138$factory = function () use ($reflector) { 139 return $reflector->newLazyGhost(function ($obj) { 140 throw new \Exception('initializer'); 141 }); 142}; 143 144test('Ghost', $factory); 145 146$factory = function () use ($reflector) { 147 return $reflector->newLazyGhost(function ($obj) { 148 throw new \Exception('initializer'); 149 }); 150}; 151 152test('Proxy', $factory); 153 154?> 155--EXPECT-- 156# Ghost: 157 158## Property [ private $priv = 'privB' ] 159 160skipInitializerForProperty(): 161getValue(): Error: Cannot access private property B::$priv 162 163setRawValueWithoutLazyInitialization(): 164getValue(): Error: Cannot access private property B::$priv 165 166## Property [ public $pubB = 'pubB' ] 167 168skipInitializerForProperty(): 169getValue(): string(4) "pubB" 170 171setRawValueWithoutLazyInitialization(): 172getValue(): string(5) "value" 173 174## Property [ private readonly string $readonly ] 175 176skipInitializerForProperty(): 177getValue(): Error: Cannot access private property B::$readonly 178 179setRawValueWithoutLazyInitialization(): 180getValue(): Error: Cannot access private property B::$readonly 181 182## Property [ protected $prot = 'prot' ] 183 184skipInitializerForProperty(): 185getValue(): Error: Cannot access protected property B::$prot 186 187setRawValueWithoutLazyInitialization(): 188getValue(): Error: Cannot access protected property B::$prot 189 190## Property [ public $pubA = 'pubA' ] 191 192skipInitializerForProperty(): 193getValue(): string(4) "pubA" 194 195setRawValueWithoutLazyInitialization(): 196getValue(): string(5) "value" 197 198## Property [ public static $static = 'static' ] 199 200skipInitializerForProperty(): 201ReflectionException: Can not use skipLazyInitialization on static property B::$static 202 203setRawValueWithoutLazyInitialization(): 204ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property B::$static 205 206## Property [ public $noDefault = NULL ] 207 208skipInitializerForProperty(): 209getValue(): NULL 210 211setRawValueWithoutLazyInitialization(): 212getValue(): string(5) "value" 213 214## Property [ public string $noDefaultTyped ] 215 216skipInitializerForProperty(): 217getValue(): Error: Typed property A::$noDefaultTyped must not be accessed before initialization 218 219setRawValueWithoutLazyInitialization(): 220getValue(): string(5) "value" 221 222## Property [ public $initialized = NULL ] 223 224skipInitializerForProperty(): 225getValue(): NULL 226 227setRawValueWithoutLazyInitialization(): 228getValue(): string(5) "value" 229 230## Property [ public $hooked = NULL ] 231 232skipInitializerForProperty(): 233getValue(): NULL 234 235setRawValueWithoutLazyInitialization(): 236getValue(): string(5) "value" 237 238## Property [ public $virtual ] 239 240skipInitializerForProperty(): 241ReflectionException: Can not use skipLazyInitialization on virtual property B::$virtual 242 243setRawValueWithoutLazyInitialization(): 244ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property B::$virtual 245 246## Property [ $dynamicProp ] 247 248skipInitializerForProperty(): 249ReflectionException: 250 251setRawValueWithoutLazyInitialization(): 252ReflectionException: 253# Proxy: 254 255## Property [ private $priv = 'privB' ] 256 257skipInitializerForProperty(): 258getValue(): Error: Cannot access private property B::$priv 259 260setRawValueWithoutLazyInitialization(): 261getValue(): Error: Cannot access private property B::$priv 262 263## Property [ public $pubB = 'pubB' ] 264 265skipInitializerForProperty(): 266getValue(): string(4) "pubB" 267 268setRawValueWithoutLazyInitialization(): 269getValue(): string(5) "value" 270 271## Property [ private readonly string $readonly ] 272 273skipInitializerForProperty(): 274getValue(): Error: Cannot access private property B::$readonly 275 276setRawValueWithoutLazyInitialization(): 277getValue(): Error: Cannot access private property B::$readonly 278 279## Property [ protected $prot = 'prot' ] 280 281skipInitializerForProperty(): 282getValue(): Error: Cannot access protected property B::$prot 283 284setRawValueWithoutLazyInitialization(): 285getValue(): Error: Cannot access protected property B::$prot 286 287## Property [ public $pubA = 'pubA' ] 288 289skipInitializerForProperty(): 290getValue(): string(4) "pubA" 291 292setRawValueWithoutLazyInitialization(): 293getValue(): string(5) "value" 294 295## Property [ public static $static = 'static' ] 296 297skipInitializerForProperty(): 298ReflectionException: Can not use skipLazyInitialization on static property B::$static 299 300setRawValueWithoutLazyInitialization(): 301ReflectionException: Can not use setRawValueWithoutLazyInitialization on static property B::$static 302 303## Property [ public $noDefault = NULL ] 304 305skipInitializerForProperty(): 306getValue(): NULL 307 308setRawValueWithoutLazyInitialization(): 309getValue(): string(5) "value" 310 311## Property [ public string $noDefaultTyped ] 312 313skipInitializerForProperty(): 314getValue(): Error: Typed property A::$noDefaultTyped must not be accessed before initialization 315 316setRawValueWithoutLazyInitialization(): 317getValue(): string(5) "value" 318 319## Property [ public $initialized = NULL ] 320 321skipInitializerForProperty(): 322getValue(): NULL 323 324setRawValueWithoutLazyInitialization(): 325getValue(): string(5) "value" 326 327## Property [ public $hooked = NULL ] 328 329skipInitializerForProperty(): 330getValue(): NULL 331 332setRawValueWithoutLazyInitialization(): 333getValue(): string(5) "value" 334 335## Property [ public $virtual ] 336 337skipInitializerForProperty(): 338ReflectionException: Can not use skipLazyInitialization on virtual property B::$virtual 339 340setRawValueWithoutLazyInitialization(): 341ReflectionException: Can not use setRawValueWithoutLazyInitialization on virtual property B::$virtual 342 343## Property [ $dynamicProp ] 344 345skipInitializerForProperty(): 346ReflectionException: 347 348setRawValueWithoutLazyInitialization(): 349ReflectionException: 350