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