@@ -17,7 +17,7 @@ class A
1717class B
1818{
1919 public int $ a ;
20- public string $ b ;
20+ public readonly string $ b ;
2121}
2222
2323class C
@@ -29,42 +29,140 @@ class D
2929{
3030}
3131
32+ class E
33+ {
34+ public function __construct (
35+ public int $ a ,
36+ public string $ b ,
37+ )
38+ {}
39+ }
40+
41+ class F
42+ {
43+ public readonly int $ a ;
44+
45+ public function __construct (
46+ public readonly string $ b ,
47+ )
48+ {}
49+ }
50+
51+ class G
52+ {
53+ public readonly int $ a ;
54+ public readonly string $ b ;
55+
56+ public function __construct ()
57+ {
58+ $ this ->b = 456 ;
59+ }
60+ }
61+
62+ class H
63+ {
64+ public int $ a {
65+ set(int $ value ) => $ value + 1 ;
66+ }
67+ }
68+
69+ class I
70+ {
71+ public int $ a ;
72+
73+ public int $ b {
74+ get => $ this ->a + 1 ;
75+ set(int $ value ) {
76+ $ this ->a = $ value - 1 ;
77+ }
78+ }
79+ }
80+
3281
3382$ rcA = new ReflectionClass ('A ' );
3483$ rcB = new ReflectionClass ('B ' );
3584$ rcC = new ReflectionClass ('C ' );
3685$ rcD = new ReflectionClass ('D ' );
86+ $ rcE = new ReflectionClass ('E ' );
87+ $ rcF = new ReflectionClass ('F ' );
88+ $ rcG = new ReflectionClass ('G ' );
89+ $ rcH = new ReflectionClass ('H ' );
90+ $ rcI = new ReflectionClass ('I ' );
3791
92+ // assign bad data type to normal class
3893try
3994{
4095 $ rcA ->newInstanceFromData (['a ' => 'bad ' , 'b ' => 123 ], ['foo ' , 1337 ]);
96+ echo "you should not see this \n" ;
4197}
4298catch (Throwable $ e )
4399{
44100 echo "Exception: " . $ e ->getMessage () . "\n" ;
45101}
46102
103+ // normal class with constructor
47104var_dump ($ rcA ->newInstanceFromData (['a ' => 123 , 'b ' => 'good ' ], ['foo ' , 1337 ]));
48105
106+ // normal class with no constructor and a readonly property
49107var_dump ($ rcB ->newInstanceFromData (['a ' => 123 , 'b ' => 'good ' ]));
50108
51- var_dump ( $ rcC -> newInstanceFromData ([ ' a ' => 123 , ' b ' => ' good ' ]));
52-
53- var_dump ($ rcC ->newInstanceFromData ([]));
109+ // trying to set dynamic properties on class without AllowDynamicProperties attribute
110+ var_dump ( $ rcC -> newInstanceFromData ([ ' a ' => 123 , ' b ' => ' good ' ])); // this should warn
111+ var_dump ($ rcC ->newInstanceFromData ([])); // this is fine
54112
113+ // setting dynamic properties on a class with AllowDynamicProperties attribute
55114var_dump ($ rcD ->newInstanceFromData (['a ' => 123 , 'b ' => 'good ' ]));
56115
116+ // class with property promotion
117+ try
118+ {
119+ $ rcE ->newInstanceFromData (['a ' => 123 , 'b ' => 'good ' ]); // no constructor args will fail
120+ echo "you should not see this \n" ;
121+ }
122+ catch (Throwable $ e )
123+ {
124+ echo "Exception: " . $ e ->getMessage () . "\n" ;
125+ }
126+
127+ var_dump ($ rcE ->newInstanceFromData (['a ' => 123 , 'b ' => 'good ' ], [456 , 'foo ' ])); // constructor args will override class props
128+
129+ // class with readonly promoted property
130+ var_dump ($ rcF ->newInstanceFromData (['a ' => 123 ], ['b ' => 'good ' ]));
131+
132+ // readonly property set in the constructor
133+ try
134+ {
135+ $ rcG ->newInstanceFromData (['a ' => 123 , 'b ' => 'good ' ]); // setting $b by data will conflict with constructor's set
136+ echo "you should not see this \n" ;
137+ }
138+ catch (Throwable $ e )
139+ {
140+ echo "Exception: " . $ e ->getMessage () . "\n" ;
141+ }
142+
143+ // hooked set property
144+ var_dump ($ rcH ->newInstanceFromData (['a ' => 1 ]));
145+
146+ // virtual property
147+ var_dump ($ rcI ->newInstanceFromData (['a ' => 1 , 'b ' => 2 ]));
148+
149+ $ instance = $ rcI ->newInstanceFromData (['a ' => 1 ]);
150+ var_dump ($ instance );
151+ var_dump ($ instance ->b );
152+ $ instance ->b = 3 ;
153+ var_dump ($ instance ->b );
154+
57155?>
58156--EXPECTF--
59157Exception: Cannot assign string to property A::$a of type int
60158In constructor of class A
61- object(A)#5 (2) {
159+ object(A)#%d (2) {
62160 ["a"]=>
63161 int(123)
64162 ["b"]=>
65163 string(4) "good"
66164}
67- object(B)#5 (2) {
165+ object(B)#%d (2) {
68166 ["a"]=>
69167 int(123)
70168 ["b"]=>
@@ -74,17 +172,45 @@ object(B)#5 (2) {
74172Deprecated: Creation of dynamic property C::$a is deprecated in %s on line %d
75173
76174Deprecated: Creation of dynamic property C::$b is deprecated in %s on line %d
77- object(C)#5 (2) {
175+ object(C)#%d (2) {
78176 ["a"]=>
79177 int(123)
80178 ["b"]=>
81179 string(4) "good"
82180}
83- object(C)#5 (0) {
181+ object(C)#%d (0) {
84182}
85- object(D)#5 (2) {
183+ object(D)#%d (2) {
86184 ["a"]=>
87185 int(123)
88186 ["b"]=>
89187 string(4) "good"
90188}
189+ Exception: Too few arguments to function E::__construct(), 0 passed and exactly 2 expected
190+ object(E)#%d (2) {
191+ ["a"]=>
192+ int(456)
193+ ["b"]=>
194+ string(3) "foo"
195+ }
196+ object(F)#%d (2) {
197+ ["a"]=>
198+ int(123)
199+ ["b"]=>
200+ string(4) "good"
201+ }
202+ Exception: Cannot modify readonly property G::$b
203+ object(H)#%d (1) {
204+ ["a"]=>
205+ int(2)
206+ }
207+ object(I)#%d (1) {
208+ ["a"]=>
209+ int(1)
210+ }
211+ object(I)#%d (1) {
212+ ["a"]=>
213+ int(1)
214+ }
215+ int(2)
216+ int(3)
0 commit comments