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