1--TEST--
2Lazy objects: resetAsLazy*() preserves readonly semantics
3--FILE--
4<?php
5
6class B {
7    public readonly int $a;
8    public readonly int $b;
9    public int $c;
10
11    public function __construct($value, bool $setB = false) {
12        try {
13            $this->a = $value;
14        } catch (\Error $e) {
15            printf("%s: %s\n", $e::class, $e->getMessage());
16        }
17        if ($setB) {
18            $this->b = $value;
19        }
20        try {
21            $this->c = $value;
22        } catch (\Error $e) {
23            printf("%s: %s\n", $e::class, $e->getMessage());
24        }
25    }
26}
27
28final class C extends B {
29}
30
31
32function test(string $name, object $obj) {
33    printf("# %s\n", $name);
34
35    $reflector = new ReflectionClass($obj::class);
36
37    $reflector->resetAsLazyGhost($obj, function ($obj) {
38        $obj->__construct(2, setB: true);
39    });
40
41    $reflector->initializeLazyObject($obj);
42
43    var_dump($obj);
44}
45
46$obj = new B(1);
47test('B', $obj);
48
49$obj = new C(1);
50test('C', $obj);
51
52--EXPECTF--
53# B
54object(B)#%d (3) {
55  ["a"]=>
56  int(2)
57  ["b"]=>
58  int(2)
59  ["c"]=>
60  int(2)
61}
62# C
63Error: Cannot modify readonly property B::$a
64object(C)#%d (3) {
65  ["a"]=>
66  int(1)
67  ["b"]=>
68  int(2)
69  ["c"]=>
70  int(2)
71}
72