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