GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — 4.2-to-master ( ed215f )
by E
06:47
created

ReflectionClass   D

Complexity

Total Complexity 105

Size/Duplication

Total Lines 603
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 12

Importance

Changes 0
Metric Value
dl 0
loc 603
rs 4.0472
c 0
b 0
f 0
wmc 105
lcom 2
cbo 12

51 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getShortName() 0 4 1
A isAbstract() 0 4 1
A isFinal() 0 4 1
A isInterface() 0 4 1
A isException() 0 4 1
A isSubclassOf() 0 4 1
C getMethods() 0 44 14
B getOwnMethods() 0 15 5
A getTraitMethods() 0 4 1
A getMethod() 0 12 2
B getProperties() 0 19 6
B getOwnProperties() 0 15 5
A getTraitProperties() 0 4 1
A getProperty() 0 12 2
B getConstants() 0 15 5
A getOwnConstants() 0 14 4
A getConstant() 0 12 2
A hasConstant() 0 4 1
A hasOwnConstant() 0 4 1
A getOwnConstant() 0 12 2
A getParentClass() 0 10 2
A getParentClassName() 0 4 1
A getParentClasses() 0 10 2
A implementsInterface() 0 4 1
A getInterfaces() 0 6 1
A getOwnInterfaces() 0 6 1
A getOwnInterfaceNames() 0 4 1
A getTraits() 0 10 2
A getTraitNames() 0 4 1
A getOwnTraitNames() 0 4 1
A getTraitAliases() 0 4 1
A getOwnTraits() 0 10 2
A isTrait() 0 4 1
A usesTrait() 0 4 1
A getDirectSubClasses() 0 12 4
B getIndirectSubClasses() 0 14 5
A getDirectImplementers() 0 8 2
A getIndirectImplementers() 0 8 2
A getDirectUsers() 0 8 2
A getIndirectUsers() 0 8 2
A getInheritedMethods() 0 4 1
A getUsedMethods() 0 5 1
A getInheritedConstants() 0 4 1
A getInheritedProperties() 0 4 1
A getUsedProperties() 0 4 1
A hasProperty() 0 8 2
A hasMethod() 0 4 1
A getVisibilityLevel() 0 4 1
A getReflectionFactory() 0 4 1
A sortUsedMethods() 0 15 2

How to fix   Complexity   

Complex Class

Complex classes like ReflectionClass often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ReflectionClass, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace ApiGen\Parser\Reflection;
4
5
use ApiGen\Contracts\Parser\Reflection\ClassReflectionInterface;
6
use ApiGen\Contracts\Parser\Reflection\ConstantReflectionInterface;
7
use ApiGen\Contracts\Parser\Reflection\Extractors\ClassTraitElementsExtractorInterface;
8
use ApiGen\Contracts\Parser\Reflection\Extractors\ParentClassElementsExtractorInterface;
9
use ApiGen\Contracts\Parser\Reflection\MethodReflectionInterface;
10
use ApiGen\Contracts\Parser\Reflection\PropertyReflectionInterface;
11
use ApiGen\Contracts\Parser\Reflection\TokenReflection\ReflectionFactoryInterface;
12
use ApiGen\Parser\Reflection\Extractors\ClassTraitElementsExtractor;
13
use ApiGen\Parser\Reflection\Extractors\ParentClassElementsExtractor;
14
use InvalidArgumentException;
15
use TokenReflection\IReflectionClass;
16
17
final class ReflectionClass extends AbstractReflectionElement implements ClassReflectionInterface
18
{
19
    /**
20
     * @var ClassReflectionInterface[]
21
     */
22
    private $parentClasses;
23
24
    /**
25
     * @var PropertyReflectionInterface[]
26
     */
27
    private $properties;
28
29
    /**
30
     * @var PropertyReflectionInterface[]
31
     */
32
    private $ownProperties;
33
34
    /**
35
     * @var ConstantReflectionInterface[]
36
     */
37
    private $constants;
38
39
    /**
40
     * @var ConstantReflectionInterface[]
41
     */
42
    private $ownConstants;
43
44
    /**
45
     * @var MethodReflectionInterface[]
46
     */
47
    private $methods;
48
49
    /**
50
     * @var MethodReflectionInterface[]
51
     */
52
    private $ownMethods;
53
54
    /**
55
     * @var ClassTraitElementsExtractorInterface
56
     */
57
    private $classTraitElementExtractor;
58
59
    /**
60
     * @var ParentClassElementsExtractorInterface
61
     */
62
    private $parentClassElementExtractor;
63
64
    /**
65
     * @param mixed $reflectionClass
66
     */
67
    public function __construct($reflectionClass)
68
    {
69
        parent::__construct($reflectionClass);
70
        $this->classTraitElementExtractor = new ClassTraitElementsExtractor($this, $reflectionClass);
71
        $this->parentClassElementExtractor = new ParentClassElementsExtractor($this);
72
    }
73
74
    public function getShortName(): string
75
    {
76
        return $this->reflection->getShortName();
77
    }
78
79
    public function isAbstract(): bool
80
    {
81
        return $this->reflection->isAbstract();
82
    }
83
84
    public function isFinal(): bool
85
    {
86
        return $this->reflection->isFinal();
87
    }
88
89
    public function isInterface(): bool
90
    {
91
        return $this->reflection->isInterface();
92
    }
93
94
    public function isException(): bool
95
    {
96
        return $this->reflection->isException();
97
    }
98
99
    public function isSubclassOf(string $class): bool
100
    {
101
        return $this->reflection->isSubclassOf($class);
102
    }
103
104
    /**
105
     * @return MethodReflectionInterface[]
106
     */
107
    public function getMethods(): array
108
    {
109
        if ($this->methods === null) {
110
            $this->methods = $this->getOwnMethods();
111
112
            foreach ($this->getOwnTraits() as $trait) {
113
                if (!$trait instanceof ReflectionClass) {
114
                    continue;
115
                }
116
117
                foreach ($trait->getOwnMethods() as $method) {
118
                    if (isset($this->methods[$method->getName()])) {
119
                        continue;
120
                    }
121
122
                    if (! $this->isDocumented() || $method->isDocumented()) {
123
                        $this->methods[$method->getName()] = $method;
124
                    }
125
                }
126
            }
127
128
            if ($this->getParentClassName() !== null) {
129
                foreach ($this->getParentClass()->getMethods() as $parentMethod) {
130
                    if (!isset($this->methods[$parentMethod->getName()])) {
131
                        $this->methods[$parentMethod->getName()] = $parentMethod;
132
                    }
133
                }
134
            }
135
136
            foreach ($this->getOwnInterfaces() as $interface) {
137
                foreach ($interface->getMethods() as $parentMethod) {
138
                    if (!isset($this->methods[$parentMethod->getName()])) {
139
                        $this->methods[$parentMethod->getName()] = $parentMethod;
140
                    }
141
                }
142
            }
143
144
            $this->methods = array_filter($this->methods, function (ReflectionMethod $method) {
145
                return $method->configuration->getVisibilityLevel() === $this->getVisibilityLevel();
0 ignored issues
show
Documentation introduced by
The property $configuration is declared protected in ApiGen\Parser\Reflection\AbstractReflection. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
146
            });
147
        }
148
149
        return $this->methods;
150
    }
151
152
    /**
153
     * @return MethodReflectionInterface[]
154
     */
155
    public function getOwnMethods(): array
156
    {
157
        if ($this->ownMethods === null) {
158
            $this->ownMethods = [];
159
160
            foreach ($this->reflection->getOwnMethods($this->getVisibilityLevel()) as $method) {
161
                $apiMethod = $this->reflectionFactory->createFromReflection($method);
162
                if (! $this->isDocumented() || $apiMethod->isDocumented()) {
163
                    $this->ownMethods[$method->getName()] = $apiMethod;
164
                }
165
            }
166
        }
167
168
        return $this->ownMethods;
169
    }
170
171
    /**
172
     * @return MethodReflectionInterface[]
173
     */
174
    public function getTraitMethods(): array
175
    {
176
        return $this->classTraitElementExtractor->getTraitMethods();
177
    }
178
179
    public function getMethod(string $name): MethodReflectionInterface
180
    {
181
        if ($this->hasMethod($name)) {
182
            return $this->methods[$name];
183
        }
184
185
        throw new InvalidArgumentException(sprintf(
186
            'Method %s does not exist in class %s',
187
            $name,
188
            $this->reflection->getName()
189
        ));
190
    }
191
192
    /**
193
     * @return PropertyReflectionInterface[]
194
     */
195
    public function getProperties(): array
196
    {
197
        if ($this->properties === null) {
198
            $this->properties = $this->getOwnProperties();
199
            foreach ($this->reflection->getProperties($this->getVisibilityLevel()) as $property) {
200
                /** @var ReflectionElement $property */
201
                if (isset($this->properties[$property->getName()])) {
202
                    continue;
203
                }
204
205
                $apiProperty = $this->reflectionFactory->createFromReflection($property);
206
                if (! $this->isDocumented() || $apiProperty->isDocumented()) {
207
                    $this->properties[$property->getName()] = $apiProperty;
208
                }
209
            }
210
        }
211
212
        return $this->properties;
213
    }
214
215
    /**
216
     * @return PropertyReflectionInterface[]
217
     */
218
    public function getOwnProperties(): array
219
    {
220
        if ($this->ownProperties === null) {
221
            $this->ownProperties = [];
222
            foreach ($this->reflection->getOwnProperties($this->getVisibilityLevel()) as $property) {
223
                $apiProperty = $this->reflectionFactory->createFromReflection($property);
224
                if (! $this->isDocumented() || $apiProperty->isDocumented()) {
225
                    /** @var ReflectionElement $property */
226
                    $this->ownProperties[$property->getName()] = $apiProperty;
227
                }
228
            }
229
        }
230
231
        return $this->ownProperties;
232
    }
233
234
    /**
235
     * @return PropertyReflectionInterface[]
236
     */
237
    public function getTraitProperties(): array
238
    {
239
        return $this->classTraitElementExtractor->getTraitProperties();
240
    }
241
242
    public function getProperty(string $name): PropertyReflectionInterface
243
    {
244
        if ($this->hasProperty($name)) {
245
            return $this->properties[$name];
246
        }
247
248
        throw new InvalidArgumentException(sprintf(
249
            'Property %s does not exist in class %s',
250
            $name,
251
            $this->reflection->getName()
252
        ));
253
    }
254
255
    /**
256
     * @return ConstantReflectionInterface[]
257
     */
258
    public function getConstants(): array
259
    {
260
        if ($this->constants === null) {
261
            $this->constants = [];
262
            foreach ($this->reflection->getConstantReflections() as $constant) {
263
                $apiConstant = $this->reflectionFactory->createFromReflection($constant);
264
                if (! $this->isDocumented() || $apiConstant->isDocumented()) {
265
                    /** @var ReflectionElement $constant */
266
                    $this->constants[$constant->getName()] = $apiConstant;
267
                }
268
            }
269
        }
270
271
        return $this->constants;
272
    }
273
274
    /**
275
     * @return ConstantReflectionInterface[]
276
     */
277
    public function getOwnConstants(): array
278
    {
279
        if ($this->ownConstants === null) {
280
            $this->ownConstants = [];
281
            $className = $this->reflection->getName();
282
            foreach ($this->getConstants() as $constantName => $constant) {
283
                if ($className === $constant->getDeclaringClassName()) {
284
                    $this->ownConstants[$constantName] = $constant;
285
                }
286
            }
287
        }
288
289
        return $this->ownConstants;
290
    }
291
292
    public function getConstant(string $name): ConstantReflectionInterface
293
    {
294
        if (isset($this->getConstants()[$name])) {
295
            return $this->getConstants()[$name];
296
        }
297
298
        throw new InvalidArgumentException(sprintf(
299
            'Constant %s does not exist in class %s',
300
            $name,
301
            $this->reflection->getName()
302
        ));
303
    }
304
305
    public function hasConstant(string $name): bool
306
    {
307
        return isset($this->getConstants()[$name]);
308
    }
309
310
    public function hasOwnConstant(string $name): bool
311
    {
312
        return isset($this->getOwnConstants()[$name]);
313
    }
314
315
    public function getOwnConstant(string $name): ConstantReflectionInterface
316
    {
317
        if (isset($this->getOwnConstants()[$name])) {
318
            return $this->getOwnConstants()[$name];
319
        }
320
321
        throw new InvalidArgumentException(sprintf(
322
            'Constant %s does not exist in class %s',
323
            $name,
324
            $this->reflection->getName()
325
        ));
326
    }
327
328
    public function getParentClass(): ?ClassReflectionInterface
329
    {
330
        $parentClassName = $this->reflection->getParentClassName();
331
332
        if ($parentClassName) {
333
            return $this->getParsedClasses()[$parentClassName];
334
        }
335
336
        return null;
337
    }
338
339
    public function getParentClassName(): ?string
340
    {
341
        return $this->reflection->getParentClassName();
342
    }
343
344
    /**
345
     * @return ClassReflectionInterface[]
346
     */
347
    public function getParentClasses(): array
348
    {
349
        if ($this->parentClasses === null) {
350
            $this->parentClasses = array_map(function (IReflectionClass $class) {
351
                return $this->getParsedClasses()[$class->getName()];
352
            }, $this->reflection->getParentClasses());
353
        }
354
355
        return $this->parentClasses;
356
    }
357
358
    public function implementsInterface(string $interface): bool
359
    {
360
        return $this->reflection->implementsInterface($interface);
361
    }
362
363
    /**
364
     * @return ClassReflectionInterface[]
365
     */
366
    public function getInterfaces(): array
367
    {
368
        return array_map(function (IReflectionClass $class) {
369
            return $this->getParsedClasses()[$class->getName()];
370
        }, $this->reflection->getInterfaces());
371
    }
372
373
    /**
374
     * @return ClassReflectionInterface[]
375
     */
376
    public function getOwnInterfaces(): array
377
    {
378
        return array_map(function (IReflectionClass $class) {
379
            return $this->getParsedClasses()[$class->getName()];
380
        }, $this->reflection->getOwnInterfaces());
381
    }
382
383
    /**
384
     * @return string[]
385
     */
386
    public function getOwnInterfaceNames(): array
387
    {
388
        return $this->reflection->getOwnInterfaceNames();
389
    }
390
391
    /**
392
     * @return ClassReflectionInterface[]
393
     */
394
    public function getTraits(): array
395
    {
396
        return array_map(function (IReflectionClass $class) {
397
            if (! isset($this->getParsedClasses()[$class->getName()])) {
398
                return $class->getName();
399
            } else {
400
                return $this->getParsedClasses()[$class->getName()];
401
            }
402
        }, $this->reflection->getTraits());
403
    }
404
405
    /**
406
     * @return string[]
407
     */
408
    public function getTraitNames(): array
409
    {
410
        return $this->reflection->getTraitNames();
411
    }
412
413
    /**
414
     * @return string[]
415
     */
416
    public function getOwnTraitNames(): array
417
    {
418
        return $this->reflection->getOwnTraitNames();
419
    }
420
421
    /**
422
     * @return string[]
423
     */
424
    public function getTraitAliases(): array
425
    {
426
        return $this->reflection->getTraitAliases();
427
    }
428
429
    /**
430
     * @return ClassReflectionInterface[]
431
     */
432
    public function getOwnTraits(): array
433
    {
434
        return array_map(function (IReflectionClass $class) {
435
            if (! isset($this->getParsedClasses()[$class->getName()])) {
436
                return $class->getName();
437
            } else {
438
                return $this->getParsedClasses()[$class->getName()];
439
            }
440
        }, $this->reflection->getOwnTraits());
441
    }
442
443
    public function isTrait(): bool
444
    {
445
        return $this->reflection->isTrait();
446
    }
447
448
    public function usesTrait(string $trait): bool
449
    {
450
        return $this->reflection->usesTrait($trait);
451
    }
452
453
    /**
454
     * @return ClassReflectionInterface[]
455
     */
456
    public function getDirectSubClasses(): array
457
    {
458
        $subClasses = [];
459
        foreach ($this->getParsedClasses() as $class) {
460
            if ($class->isDocumented() && $this->getName() === $class->getParentClassName()) {
461
                $subClasses[] = $class;
462
            }
463
        }
464
465
        uksort($subClasses, 'strcasecmp');
466
        return $subClasses;
467
    }
468
469
    /**
470
     * @return ClassReflectionInterface[]
471
     */
472
    public function getIndirectSubClasses(): array
473
    {
474
        $subClasses = [];
475
        foreach ($this->getParsedClasses() as $class) {
476
            if ($class->isDocumented() && $this->getName() !== $class->getParentClassName()
477
                && $class->isSubclassOf($this->getName())
478
            ) {
479
                $subClasses[] = $class;
480
            }
481
        }
482
483
        uksort($subClasses, 'strcasecmp');
484
        return $subClasses;
485
    }
486
487
    /**
488
     * @return ClassReflectionInterface[]
489
     */
490
    public function getDirectImplementers(): array
491
    {
492
        if (! $this->isInterface()) {
493
            return [];
494
        }
495
496
        return $this->parserStorage->getDirectImplementersOfInterface($this);
497
    }
498
499
    /**
500
     * @return ClassReflectionInterface[]
501
     */
502
    public function getIndirectImplementers(): array
503
    {
504
        if (! $this->isInterface()) {
505
            return [];
506
        }
507
508
        return $this->parserStorage->getIndirectImplementersOfInterface($this);
509
    }
510
511
    /**
512
     * @return ClassReflectionInterface[]
513
     */
514
    public function getDirectUsers(): array
515
    {
516
        if (! $this->isTrait()) {
517
            return [];
518
        }
519
520
        return $this->classTraitElementExtractor->getDirectUsers();
521
    }
522
523
    /**
524
     * @return ClassReflectionInterface[]
525
     */
526
    public function getIndirectUsers(): array
527
    {
528
        if (! $this->isTrait()) {
529
            return [];
530
        }
531
532
        return $this->classTraitElementExtractor->getIndirectUsers();
533
    }
534
535
    /**
536
     * @return MethodReflectionInterface[]
537
     */
538
    public function getInheritedMethods(): array
539
    {
540
        return $this->parentClassElementExtractor->getInheritedMethods();
541
    }
542
543
    /**
544
     * @return MethodReflectionInterface[]
545
     */
546
    public function getUsedMethods(): array
547
    {
548
        $usedMethods = $this->classTraitElementExtractor->getUsedMethods();
549
        return $this->sortUsedMethods($usedMethods);
550
    }
551
552
    /**
553
     * @return ConstantReflectionInterface[]
554
     */
555
    public function getInheritedConstants(): array
556
    {
557
        return $this->parentClassElementExtractor->getInheritedConstants();
558
    }
559
560
    /**
561
     * @return PropertyReflectionInterface[]
562
     */
563
    public function getInheritedProperties(): array
564
    {
565
        return $this->parentClassElementExtractor->getInheritedProperties();
566
    }
567
568
    /**
569
     * @return PropertyReflectionInterface[]
570
     */
571
    public function getUsedProperties(): array
572
    {
573
        return $this->classTraitElementExtractor->getUsedProperties();
574
    }
575
576
    public function hasProperty(string $name): bool
577
    {
578
        if ($this->properties === null) {
579
            $this->getProperties();
580
        }
581
582
        return isset($this->properties[$name]);
583
    }
584
585
    public function hasMethod(string $name): bool
586
    {
587
        return isset($this->getMethods()[$name]);
588
    }
589
590
    public function getVisibilityLevel(): int
591
    {
592
        return $this->configuration->getVisibilityLevel();
593
    }
594
595
    public function getReflectionFactory(): ReflectionFactoryInterface
596
    {
597
        return $this->reflectionFactory;
598
    }
599
600
    /**
601
     * @param mixed[] $usedMethods
602
     * @return mixed[]
603
     */
604
    private function sortUsedMethods(array $usedMethods): array
605
    {
606
        array_walk($usedMethods, function (&$methods) {
607
            ksort($methods);
608
            array_walk($methods, function (&$aliasedMethods) {
609
                if (! isset($aliasedMethods['aliases'])) {
610
                    $aliasedMethods['aliases'] = [];
611
                }
612
613
                ksort($aliasedMethods['aliases']);
614
            });
615
        });
616
617
        return $usedMethods;
618
    }
619
}
620