1--TEST-- 2Lazy objects: setRawValueWithoutLazyInitialization() may trigger initialization via side effects (__toString()) 3--FILE-- 4<?php 5 6class C { 7 public function __construct() { 8 printf("%s\n", __METHOD__); 9 $this->a = 'a'; 10 $this->b = 'b'; 11 } 12 public string $a; 13 public string $b; 14} 15 16function test(string $name, object $obj) { 17 printf("# %s\n", $name); 18 19 $reflector = new ReflectionClass(C::class); 20 21 $value = new class($obj) { 22 function __construct(public object $obj) {} 23 function __toString() { 24 return $this->obj->b; 25 } 26 }; 27 $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $value); 28 29 var_dump(!$reflector->isUninitializedLazyObject($obj)); 30 var_dump($obj); 31} 32 33$reflector = new ReflectionClass(C::class); 34$obj = $reflector->newLazyGhost(function ($obj) { 35 $obj->__construct(); 36}); 37 38test('Ghost', $obj); 39 40$obj = $reflector->newLazyProxy(function () { 41 return new C(); 42}); 43 44test('Proxy', $obj); 45 46?> 47--EXPECTF-- 48# Ghost 49C::__construct 50bool(true) 51object(C)#%d (2) { 52 ["a"]=> 53 string(1) "b" 54 ["b"]=> 55 string(1) "b" 56} 57# Proxy 58C::__construct 59bool(true) 60lazy proxy object(C)#%d (1) { 61 ["instance"]=> 62 object(C)#%d (2) { 63 ["a"]=> 64 string(1) "a" 65 ["b"]=> 66 string(1) "b" 67 } 68} 69