14
14
15
15
use Closure ;
16
16
use margusk \Accessors \Exception \InvalidArgumentException ;
17
- use PHPStan \PhpDocParser \Parser \PhpDocParser ;
18
- use PHPStan \PhpDocParser \Parser \TypeParser ;
19
- use PHPStan \PhpDocParser \Parser \ConstExprParser ;
20
- use PHPStan \PhpDocParser \Parser \TokenIterator ;
21
- use PHPStan \PhpDocParser \Lexer \Lexer ;
22
- use PHPStan \PhpDocParser \Ast \PhpDoc \PhpDocTagNode ;
23
- use PHPStan \PhpDocParser \Ast \PhpDoc \PropertyTagValueNode ;
24
17
use ReflectionClass ;
25
18
use ReflectionException ;
26
- use ReflectionMethod ;
27
- use ReflectionProperty ;
28
19
29
20
use function call_user_func ;
30
21
use function get_parent_class ;
31
- use function is_string ;
32
- use function preg_match ;
33
- use function str_starts_with ;
34
- use function strtolower ;
35
- use function substr ;
36
22
37
23
final class ClassConf
38
24
{
@@ -42,14 +28,8 @@ final class ClassConf
42
28
/** @var Attributes */
43
29
private Attributes $ attributes ;
44
30
45
- /** @var ReflectionClass<object> */
46
- private ReflectionClass $ rfClass ;
47
-
48
- /** @var Property[] */
49
- private array $ properties = [];
50
-
51
- /** @var Property[] */
52
- private array $ propertiesByLcase = [];
31
+ /** @var Properties */
32
+ private Properties $ properties ;
53
33
54
34
/** @var Closure */
55
35
private Closure $ getter ;
@@ -72,71 +52,21 @@ private function __construct(
72
52
protected string $ name
73
53
) {
74
54
/* Verify that the specified class is valid in every aspect */
75
- $ this -> rfClass = new ReflectionClass ($ this ->name );
55
+ $ rfClass = new ReflectionClass ($ this ->name );
76
56
77
- /* Parse attributes of current class */
78
- $ this ->attributes = Attributes::fromReflection ($ this -> rfClass );
57
+ /* First parse attributes of current class */
58
+ $ this ->attributes = Attributes::fromReflection ($ rfClass );
79
59
80
- /* Require parent class to be parsed before current class , ... */
60
+ /* Next require parent class to be initialized before current, ... */
81
61
$ parentName = get_parent_class ($ this ->name );
82
62
83
- /* ...because attributes from current class need to be merged with parent one's */
63
+ /* ...because attributes from parent class need to be merged into current */
84
64
if (false !== $ parentName ) {
85
65
$ parent = self ::factory ($ parentName );
86
66
$ this ->attributes = $ this ->attributes ->mergeWithParent ($ parent ->attributes );
87
67
}
88
68
89
- /* Learn from DocBlock comments which properties should be exposed and how (read-only,write-only or both) */
90
- $ docBlockAttributes = $ this ->parseDocBlock ($ this ->rfClass );
91
-
92
- /**
93
- * Collect all manual accessor endpoints.
94
- *
95
- * @var array<string, array<string, string>> $accessorEndpoints
96
- */
97
- $ accessorEndpoints = [];
98
-
99
- foreach (
100
- $ this ->rfClass ->getMethods (
101
- ReflectionMethod::IS_PROTECTED | ReflectionMethod::IS_PRIVATE | ReflectionMethod::IS_PUBLIC
102
- ) as $ rfMethod
103
- ) {
104
- if (!$ rfMethod ->isStatic ()
105
- && preg_match (
106
- '/^(set|get|isset|unset|with)(.+)/ ' ,
107
- strtolower ($ rfMethod ->name ),
108
- $ matches
109
- )
110
- ) {
111
- $ accessorEndpoints [(string )$ matches [2 ]][(string )$ matches [1 ]] = $ rfMethod ->name ;
112
- }
113
- }
114
-
115
- /**
116
- * Find all class properties.
117
- *
118
- * Provide accessor functionality only for private and protected properties.
119
- *
120
- * Although accessors for public properties are not provided (because it makes the behaviour unconsistent),
121
- * we'll need to remember them along with private and protected properties, so in case they are accessed,
122
- * informative error can be reported.
123
- */
124
- foreach (
125
- $ this ->rfClass ->getProperties (
126
- ReflectionMethod::IS_PRIVATE | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PUBLIC
127
- ) as $ rfProperty
128
- ) {
129
- $ name = $ rfProperty ->getName ();
130
- $ nameLowerCase = strtolower ($ name );
131
-
132
- $ this ->properties [$ name ] = new Property (
133
- $ rfProperty ,
134
- ($ docBlockAttributes [$ name ] ?? $ this ->attributes ),
135
- ($ accessorEndpoints [$ nameLowerCase ] ?? [])
136
- );
137
-
138
- $ this ->propertiesByLcase [$ nameLowerCase ] = $ this ->properties [$ name ];
139
- }
69
+ $ this ->properties = new Properties ($ rfClass , $ this ->attributes );
140
70
141
71
$ this ->getter = $ this ->createGetter ();
142
72
$ this ->setter = $ this ->createSetter ();
@@ -195,7 +125,9 @@ private function createSetter(): Closure
195
125
if (null !== $ endpoint ) {
196
126
$ result = $ object ->{$ endpoint }($ value );
197
127
198
- if ('with ' === $ accessorMethod && ($ result instanceof (self ::class))
128
+ if (
129
+ 'with ' === $ accessorMethod
130
+ && ($ result instanceof (self ::class))
199
131
) {
200
132
$ object = $ result ;
201
133
}
@@ -291,15 +223,9 @@ public static function factory(string $name): ClassConf
291
223
return self ::$ classes [$ name ];
292
224
}
293
225
294
- public function findPropertyConf ( string $ name , bool $ caseInsensitiveSearch = false ): ? Property
226
+ public function properties ( ): Properties
295
227
{
296
- if ($ caseInsensitiveSearch ) {
297
- $ propertyConf = $ this ->propertiesByLcase [strtolower ($ name )] ?? null ;
298
- } else {
299
- $ propertyConf = $ this ->properties [$ name ] ?? null ;
300
- }
301
-
302
- return $ propertyConf ;
228
+ return $ this ->properties ;
303
229
}
304
230
305
231
public function getGetter (): Closure
@@ -321,56 +247,4 @@ public function getUnSetter(): Closure
321
247
{
322
248
return $ this ->unSetter ;
323
249
}
324
-
325
- /**
326
- * @param ReflectionClass<object> $rfClass
327
- *
328
- * @return array<string, Attributes>
329
- */
330
- private function parseDocBlock (ReflectionClass $ rfClass ): array
331
- {
332
- static $ docBlockParser = null ;
333
- static $ docBlockLexer = null ;
334
-
335
- $ docComment = $ rfClass ->getDocComment ();
336
-
337
- if (!is_string ($ docComment )) {
338
- return [];
339
- }
340
-
341
- if (null === $ docBlockParser ) {
342
- $ constExprParser = new ConstExprParser ();
343
-
344
- $ docBlockParser = new PhpDocParser (
345
- new TypeParser ($ constExprParser ),
346
- $ constExprParser
347
- );
348
-
349
- $ docBlockLexer = new Lexer ();
350
- }
351
-
352
- $ node = $ docBlockParser ->parse (
353
- new TokenIterator (
354
- $ docBlockLexer ->tokenize ($ docComment )
355
- )
356
- );
357
-
358
- $ result = [];
359
-
360
- foreach ($ node ->children as $ childNode ) {
361
- if ($ childNode instanceof PhpDocTagNode
362
- && $ childNode ->value instanceof PropertyTagValueNode
363
- && str_starts_with ($ childNode ->value ->propertyName , '$ ' )) {
364
-
365
- $ attributes = Attributes::fromDocBlock ($ childNode );
366
-
367
- if (null !== $ attributes ) {
368
- $ attributes ->mergeWithParent ($ this ->attributes );
369
- $ result [substr ($ childNode ->value ->propertyName , 1 )] = $ attributes ;
370
- }
371
- }
372
- }
373
-
374
- return $ result ;
375
- }
376
250
}
0 commit comments