@@ -32,13 +32,16 @@ class Caster
32
32
public const EXCLUDE_EMPTY = 128 ;
33
33
public const EXCLUDE_NOT_IMPORTANT = 256 ;
34
34
public const EXCLUDE_STRICT = 512 ;
35
+ public const EXCLUDE_UNINITIALIZED = 1024 ;
35
36
36
37
public const PREFIX_VIRTUAL = "\0~ \0" ;
37
38
public const PREFIX_DYNAMIC = "\0+ \0" ;
38
39
public const PREFIX_PROTECTED = "\0* \0" ;
39
40
// usage: sprintf(Caster::PATTERN_PRIVATE, $class, $property)
40
41
public const PATTERN_PRIVATE = "\0%s \0%s " ;
41
42
43
+ private static array $ classProperties = [];
44
+
42
45
/**
43
46
* Casts objects to arrays and adds the dynamic property prefix.
44
47
*
@@ -61,20 +64,17 @@ public static function castObject(object $obj, string $class, bool $hasDebugInfo
61
64
return $ a ;
62
65
}
63
66
67
+ $ classProperties = self ::$ classProperties [$ class ] ??= self ::getClassProperties (new \ReflectionClass ($ class ));
68
+ $ a = array_replace ($ classProperties , $ a );
69
+
64
70
if ($ a ) {
65
- static $ publicProperties = [];
66
71
$ debugClass ??= get_debug_type ($ obj );
67
72
68
73
$ i = 0 ;
69
74
$ prefixedKeys = [];
70
75
foreach ($ a as $ k => $ v ) {
71
76
if ("\0" !== ($ k [0 ] ?? '' )) {
72
- if (!isset ($ publicProperties [$ class ])) {
73
- foreach ((new \ReflectionClass ($ class ))->getProperties (\ReflectionProperty::IS_PUBLIC ) as $ prop ) {
74
- $ publicProperties [$ class ][$ prop ->name ] = true ;
75
- }
76
- }
77
- if (!isset ($ publicProperties [$ class ][$ k ])) {
77
+ if (!isset ($ classProperties [$ k ])) {
78
78
$ prefixedKeys [$ i ] = self ::PREFIX_DYNAMIC .$ k ;
79
79
}
80
80
} elseif ($ debugClass !== $ class && 1 === strpos ($ k , $ class )) {
@@ -131,6 +131,8 @@ public static function filter(array $a, int $filter, array $listedProperties = [
131
131
$ type |= self ::EXCLUDE_EMPTY & $ filter ;
132
132
} elseif (false === $ v || '' === $ v || '0 ' === $ v || 0 === $ v || 0.0 === $ v || [] === $ v ) {
133
133
$ type |= self ::EXCLUDE_EMPTY & $ filter ;
134
+ } elseif ($ v instanceof UninitializedStub) {
135
+ $ type |= self ::EXCLUDE_UNINITIALIZED & $ filter ;
134
136
}
135
137
if ((self ::EXCLUDE_NOT_IMPORTANT & $ filter ) && !\in_array ($ k , $ listedProperties , true )) {
136
138
$ type |= self ::EXCLUDE_NOT_IMPORTANT ;
@@ -169,4 +171,28 @@ public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array
169
171
170
172
return $ a ;
171
173
}
174
+
175
+ private static function getClassProperties (\ReflectionClass $ class ): array
176
+ {
177
+ $ classProperties = [];
178
+ $ className = $ class ->name ;
179
+
180
+ foreach ($ class ->getProperties () as $ p ) {
181
+ if ($ p ->isStatic ()) {
182
+ continue ;
183
+ }
184
+
185
+ $ classProperties [match (true ) {
186
+ $ p ->isPublic () => $ p ->name ,
187
+ $ p ->isProtected () => self ::PREFIX_PROTECTED .$ p ->name ,
188
+ default => "\0" .$ className ."\0" .$ p ->name ,
189
+ }] = new UninitializedStub ($ p );
190
+ }
191
+
192
+ if ($ parent = $ class ->getParentClass ()) {
193
+ $ classProperties += self ::$ classProperties [$ parent ->name ] ??= self ::getClassProperties ($ parent );
194
+ }
195
+
196
+ return $ classProperties ;
197
+ }
172
198
}
0 commit comments