Completed
Push — master ( ecebf9...83c0fc )
by Alexander
03:38
created

ReflectionClassLikeTrait   D

Complexity

Total Complexity 130

Size/Duplication

Total Lines 826
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 11

Test Coverage

Coverage 69.74%

Importance

Changes 7
Bugs 2 Features 2
Metric Value
wmc 130
lcom 2
cbo 11
dl 0
loc 826
ccs 242
cts 347
cp 0.6974
rs 4
c 7
b 2
f 2

48 Methods

Rating   Name   Duplication   Size   Complexity  
A getProperty() 0 11 3
A getShortName() 0 4 1
A getStartLine() 0 4 1
A getTraitNames() 0 4 1
A hasConstant() 0 7 2
A hasMethod() 0 11 3
A hasProperty() 0 11 3
A implementsInterface() 0 6 1
A inNamespace() 0 4 1
D __toString() 0 89 16
A getConstant() 0 8 2
A getConstants() 0 14 2
A getConstructor() 0 9 2
C getDefaultProperties() 0 26 7
A getDocComment() 0 4 2
A getEndLine() 0 4 1
A getExtension() 0 4 1
A getExtensionName() 0 4 1
A getFileName() 0 4 1
A getInterfaceNames() 0 4 1
A getInterfaces() 0 13 3
A getMethod() 0 11 3
A getMethods() 0 15 2
A getName() 0 6 2
A getNamespaceName() 0 4 1
B getParentClass() 0 17 5
C getProperties() 0 33 7
A getTraits() 0 8 2
B isAbstract() 0 12 6
A isAnonymous() 0 4 1
A isCloneable() 0 12 4
A isFinal() 0 6 2
A isInstance() 0 10 3
A isInstantiable() 0 12 4
A isInterface() 0 4 1
A isInternal() 0 5 1
A isIterateable() 0 4 1
C isSubclassOf() 0 23 7
A isTrait() 0 4 1
A isUserDefined() 0 5 1
B getStaticProperties() 0 21 5
A getStaticPropertyValue() 0 11 4
A newInstance() 0 6 1
A newInstanceArgs() 0 7 1
A newInstanceWithoutConstructor() 0 7 1
A setStaticPropertyValue() 0 6 1
A recursiveCollect() 0 16 3
B findConstants() 0 20 5

How to fix   Complexity   

Complex Class

Complex classes like ReflectionClassLikeTrait 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 ReflectionClassLikeTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Parser Reflection API
4
 *
5
 * @copyright Copyright 2015, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\ParserReflection\Traits;
12
13
use Go\ParserReflection\ReflectionClass;
14
use Go\ParserReflection\ReflectionException;
15
use Go\ParserReflection\ReflectionMethod;
16
use Go\ParserReflection\ReflectionProperty;
17
use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
18
use PhpParser\Node\Name\FullyQualified;
19
use PhpParser\Node\Stmt\Class_;
20
use PhpParser\Node\Stmt\ClassConst;
21
use PhpParser\Node\Stmt\ClassLike;
22
use PhpParser\Node\Stmt\Interface_;
23
use PhpParser\Node\Stmt\Trait_;
24
25
/**
26
 * General class-like reflection
27
 */
28
trait ReflectionClassLikeTrait
29
{
30
    use InitializationTrait;
31
32
    /**
33
     * @var ClassLike
34
     */
35
    protected $classLikeNode;
36
37
    /**
38
     * Short name of the class, without namespace
39
     *
40
     * @var string
41
     */
42
    protected $className;
43
44
    /**
45
     * List of all constants from the class
46
     *
47
     * @var array
48
     */
49
    protected $constants;
50
51
    /**
52
     * Interfaces, empty array or null if not initialized yet
53
     *
54
     * @var \ReflectionClass[]|array|null
55
     */
56
    protected $interfaceClasses;
57
58
    /**
59
     * List of traits, empty array or null if not initialized yet
60
     *
61
     * @var  \ReflectionClass[]|array|null
62
     */
63
    protected $traits;
64
65
    /**
66
     * @var array|ReflectionMethod[]
67
     */
68
    protected $methods;
69
70
    /**
71
     * Namespace name
72
     *
73
     * @var string
74
     */
75
    protected $namespaceName = '';
76
77
    /**
78
     * Parent class, or false if not present, null if uninitialized yet
79
     *
80
     * @var \ReflectionClass|false|null
81
     */
82
    protected $parentClass;
83
84
    /**
85
     * @var array|ReflectionProperty[]
86
     */
87
    protected $properties;
88
89
    /**
90
     * Returns the string representation of the ReflectionClass object.
91
     *
92
     * @return string
93
     */
94
    public function __toString()
95
    {
96
        $isObject = $this instanceof \ReflectionObject;
97
98
        $staticProperties = $staticMethods = $defaultProperties = $dynamicProperties = $methods = [];
99
100
        $format  = "%s [ <user> %sclass %s%s%s ] {\n";
101
        $format .= "  @@ %s %d-%d\n\n";
102
        $format .= "  - Constants [%d] {%s\n  }\n\n";
103
        $format .= "  - Static properties [%d] {%s\n  }\n\n";
104
        $format .= "  - Static methods [%d] {%s\n  }\n\n";
105
        $format .= "  - Properties [%d] {%s\n  }\n\n";
106
        $format .= ($isObject ? "  - Dynamic properties [%d] {%s\n  }\n\n" : '%s%s');
107
        $format .= "  - Methods [%d] {%s\n  }\n";
108
        $format .= "}\n";
109
110
        foreach ($this->getProperties() as $property) {
111
            if ($property->isStatic()) {
112
                $staticProperties[] = $property;
113
            } elseif ($property->isDefault()) {
114
                $defaultProperties[] = $property;
115
            } else {
116
                $dynamicProperties[] = $property;
117
            }
118
        }
119
120
        foreach ($this->getMethods() as $method) {
121
            if ($method->isStatic()) {
122
                $staticMethods[] = $method;
123
            } else {
124
                $methods[] = $method;
125
            }
126
        }
127
128
        $buildString = function (array $items, $indentLevel = 4) {
129
            if (!count($items)) {
130
                return '';
131
            }
132
            $indent = "\n" . str_repeat(' ', $indentLevel);
133
            return $indent . implode($indent, explode("\n", implode("\n", $items)));
134
        };
135
        $buildConstants = function (array $items, $indentLevel = 4) {
136
            $str = '';
137
            foreach ($items as $name => $value) {
138
                $str .= "\n" . str_repeat(' ', $indentLevel);
139
                $str .= sprintf(
140
                    'Constant [ %s %s ] { %s }',
141
                    gettype($value),
142
                    $name,
143
                    $value
144
                );
145
            }
146
            return $str;
147
        };
148
        $interfaceNames = $this->getInterfaceNames();
149
        $parentClass    = $this->getParentClass();
150
        $modifiers      = '';
151
        if ($this->isAbstract()) {
152
            $modifiers = 'abstract ';
153
        } elseif ($this->isFinal()) {
154
            $modifiers = 'final ';
155
        };
156
157
        $string = sprintf(
158
            $format,
159
            ($isObject ? 'Object of class' : 'Class'),
160
            $modifiers,
161
            $this->getName(),
162
            false !== $parentClass ? (' extends ' . $parentClass->getName()) : '',
163
            $interfaceNames ? (' implements ' . implode(', ', $interfaceNames)) : '',
164
            $this->getFileName(),
165
            $this->getStartLine(),
166
            $this->getEndLine(),
167
            count($this->getConstants()),
168
            $buildConstants($this->getConstants()),
169
            count($staticProperties),
170
            $buildString($staticProperties),
171
            count($staticMethods),
172
            $buildString($staticMethods),
173
            count($defaultProperties),
174
            $buildString($defaultProperties),
175
            $isObject ? count($dynamicProperties) : '',
176
            $isObject ? $buildString($dynamicProperties) : '',
177
            count($methods),
178
            $buildString($methods)
179
        );
180
181
        return $string;
182
    }
183
184
185
    /**
186
     * {@inheritDoc}
187
     */
188 3
    public function getConstant($name)
189
    {
190 3
        if ($this->hasConstant($name)) {
191 3
            return $this->constants[$name];
192
        }
193
194
        return false;
195
    }
196
197
    /**
198
     * {@inheritDoc}
199
     */
200 3
    public function getConstants()
201
    {
202 3
        if (!isset($this->constants)) {
203 3
            $directConstants = $this->findConstants();
204
            $parentConstants = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance) {
205 2
                $result += $instance->getConstants();
206 3
            });
207 3
            $constants = $directConstants + $parentConstants;
208
209 3
            $this->constants = $constants;
210 3
        }
211
212 3
        return $this->constants;
213
    }
214
215
    /**
216
     * {@inheritDoc}
217
     */
218 2
    public function getConstructor()
219
    {
220 2
        $constructor = $this->getMethod('__construct');
221 2
        if (!$constructor) {
222 2
            return null;
223
        }
224
225 1
        return $constructor;
226
    }
227
228
    /**
229
     * Gets default properties from a class (including inherited properties). 
230
     *
231
     * @link http://php.net/manual/en/reflectionclass.getdefaultproperties.php
232
     *
233
     * @return array An array of default properties, with the key being the name of the property and the value being
234
     * the default value of the property or NULL if the property doesn't have a default value
235
     */
236 2
    public function getDefaultProperties()
237
    {
238 2
        $defaultValues = [];
239 2
        $properties    = $this->getProperties();
240 2
        $staticOrder   = [true, false];
241 2
        foreach ($staticOrder as $shouldBeStatic) {
242 2
            foreach ($properties as $property) {
243 1
                $isStaticProperty     = $property->isStatic();
244 1
                if ($shouldBeStatic !== $isStaticProperty) {
245 1
                    continue;
246
                }
247 1
                $propertyName         = $property->getName();
248 1
                $isInternalReflection = get_class($property) == \ReflectionProperty::class;
249
250 1
                if (!$isInternalReflection || $isStaticProperty) {
251 1
                    $defaultValues[$propertyName] = $property->getValue();
252 1
                } elseif (!$isStaticProperty) {
253
                    // Internal reflection and dynamic property
254 1
                    $classProperties = $property->getDeclaringClass()->getDefaultProperties();
255 1
                    $defaultValues[$propertyName] = $classProperties[$propertyName];
256 1
                }
257 2
            }
258 2
        }
259
260 2
        return $defaultValues;
261
    }
262
263
    /**
264
     * {@inheritDoc}
265
     */
266 2
    public function getDocComment()
267
    {
268 2
        return $this->classLikeNode->getDocComment() ?: false;
269
    }
270
271 2
    public function getEndLine()
272
    {
273 2
        return $this->classLikeNode->getAttribute('endLine');
274
    }
275
276 2
    public function getExtension()
277
    {
278 2
        return null;
279
    }
280
281 2
    public function getExtensionName()
282
    {
283 2
        return false;
284
    }
285
286 5
    public function getFileName()
287
    {
288 5
        return $this->classLikeNode->getAttribute('fileName');
289
    }
290
291
    /**
292
     * {@inheritDoc}
293
     */
294 2
    public function getInterfaceNames()
295
    {
296 2
        return array_keys($this->getInterfaces());
297
    }
298
299
    /**
300
     * {@inheritDoc}
301
     */
302 2
    public function getInterfaces()
303
    {
304 2
        if (!isset($this->interfaceClasses)) {
305
            $this->interfaceClasses = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance) {
306 2
                if ($instance->isInterface()) {
307 1
                    $result[$instance->name] = $instance;
308 1
                }
309 2
                $result += $instance->getInterfaces();
310 2
            });
311 2
        }
312
313 2
        return $this->interfaceClasses;
314
    }
315
316
    /**
317
     * {@inheritdoc}
318
     */
319 5
    public function getMethod($name)
320
    {
321 5
        $methods = $this->getMethods();
322 5
        foreach ($methods as $method) {
323 4
            if ($method->getName() == $name) {
324 4
                return $method;
325
            }
326 3
        }
327
328 2
        return false;
329
    }
330
331
    /**
332
     * Returns list of reflection methods
333
     *
334
     * @return ReflectionMethod[]|array
335
     */
336 6
    public function getMethods($filter = null)
0 ignored issues
show
Unused Code introduced by
The parameter $filter is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
337
    {
338 6
        if (!isset($this->methods)) {
339 6
            $directMethods = ReflectionMethod::collectFromClassNode($this->classLikeNode, $this->getName());
340
            $parentMethods = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance) {
341 3
                $result = array_merge($result, $instance->getMethods());
342 6
            });
343 6
            $methods = array_merge($directMethods, $parentMethods);
344
345 6
            $this->methods = $methods;
346 6
        }
347
        // TODO: Implement filtration of methods
348
349 6
        return $this->methods;
350
    }
351
352
    /**
353
     * {@inheritDoc}
354
     */
355 14
    public function getName()
356
    {
357 14
        $namespaceName = $this->namespaceName ? $this->namespaceName . '\\' : '';
358
359 14
        return $namespaceName . $this->getShortName();
360
    }
361
362
    /**
363
     * {@inheritDoc}
364
     */
365 5
    public function getNamespaceName()
366
    {
367 5
        return $this->namespaceName;
368
    }
369
370
    /**
371
     * {@inheritDoc}
372
     */
373 9
    public function getParentClass()
374
    {
375 9
        if (!isset($this->parentClass)) {
376 9
            static $extendsField = 'extends';
377
378 9
            $parentClass = false;
379 9
            $hasExtends  = in_array($extendsField, $this->classLikeNode->getSubNodeNames());
380 9
            $extendsNode = $hasExtends ? $this->classLikeNode->$extendsField : null;
381 9
            if ($extendsNode instanceof FullyQualified) {
382 3
                $extendsName = $extendsNode->toString();
383 3
                $parentClass = class_exists($extendsName, false) ? new parent($extendsName) : new static($extendsName);
0 ignored issues
show
Unused Code introduced by
The call to ReflectionClassLikeTrait::__construct() has too many arguments starting with $extendsName.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
384 3
            }
385 9
            $this->parentClass = $parentClass;
386 9
        }
387
388 9
        return $this->parentClass;
389
    }
390
391
    /**
392
     * Retrieves reflected properties.
393
     *
394
     * @param int $filter The optional filter, for filtering desired property types.
395
     *                    It's configured using the ReflectionProperty constants, and defaults to all property types.
396
     *
397
     * @return array|\Go\ParserReflection\ReflectionProperty[]
398
     */
399 5
    public function getProperties($filter = null)
400
    {
401 5
        if (!isset($this->properties)) {
402 5
            $directProperties = ReflectionProperty::collectFromClassNode($this->classLikeNode, $this->getName());
403 5
            $parentProperties = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance) {
404 2
                $reflectionProperties = [];
405 2
                foreach ($instance->getProperties() as $reflectionProperty) {
406 1
                    if (!$reflectionProperty->isPrivate()) {
407 1
                        $reflectionProperties[$reflectionProperty->name] = $reflectionProperty;
408 1
                    }
409 2
                }
410 2
                $result += $reflectionProperties;
411 5
            });
412 5
            $properties = $directProperties + $parentProperties;
413
414 5
            $this->properties = $properties;
415 5
        }
416
417
        // Without filter we can just return the full list
418 5
        if (!isset($filter)) {
419 5
            return array_values($this->properties);
420
        }
421
422 2
        $properties = [];
423 2
        foreach ($this->properties as $property) {
424 1
            if (!($filter & $property->getModifiers())) {
425 1
                continue;
426
            }
427 1
            $properties[] = $property;
428 2
        }
429
430 2
        return $properties;
431
    }
432
433
    /**
434
     * {@inheritdoc}
435
     */
436 3
    public function getProperty($name)
437
    {
438 3
        $properties = $this->getProperties();
439 3
        foreach ($properties as $property) {
440 3
            if ($property->getName() == $name) {
441 3
                return $property;
442
            }
443 3
        }
444
445
        return false;
446
    }
447
448
    /**
449
     * {@inheritDoc}
450
     */
451 14
    public function getShortName()
452
    {
453 14
        return $this->className;
454
    }
455
456 2
    public function getStartLine()
457
    {
458 2
        return $this->classLikeNode->getAttribute('startLine');
459
    }
460
461
    /**
462
     * Returns an array of names of traits used by this class
463
     *
464
     * @link http://php.net/manual/en/reflectionclass.gettraitnames.php
465
     *
466
     * @return array
467
     */
468 2
    public function getTraitNames()
469
    {
470 2
        return array_keys($this->getTraits());
471
    }
472
473
    /**
474
     * Returns an array of traits used by this class
475
     *
476
     * @link http://php.net/manual/en/reflectionclass.gettraits.php
477
     *
478
     * @return array|\ReflectionClass[]
479
     */
480 2
    public function getTraits()
481
    {
482 2
        if (!isset($this->traits)) {
483 2
            $this->traits = ReflectionClass::collectTraitsFromClassNode($this->classLikeNode);
484 2
        }
485
486 2
        return $this->traits;
487
    }
488
489
    /**
490
     * {@inheritDoc}
491
     */
492 3
    public function hasConstant($name)
493
    {
494 3
        $constants   = $this->getConstants();
495 3
        $hasConstant = isset($constants[$name]) || array_key_exists($constants, $name);
496
497 3
        return $hasConstant;
498
    }
499
500
    /**
501
     * {@inheritdoc}
502
     */
503 4
    public function hasMethod($name)
504
    {
505 4
        $methods = $this->getMethods();
506 4
        foreach ($methods as $method) {
507 3
            if ($method->getName() == $name) {
508 3
                return true;
509
            }
510 2
        }
511
512 2
        return false;
513
    }
514
515
    /**
516
     * {@inheritdoc}
517
     */
518
    public function hasProperty($name)
519
    {
520
        $properties = $this->getProperties();
521
        foreach ($properties as $property) {
522
            if ($property->getName() == $name) {
523
                return true;
524
            }
525
        }
526
527
        return false;
528
    }
529
530
    /**
531
     * {@inheritDoc}
532
     */
533 2
    public function implementsInterface($interfaceName)
534
    {
535 2
        $allInterfaces = $this->getInterfaces();
536
537 2
        return isset($allInterfaces[$interfaceName]);
538
    }
539
540
    /**
541
     * {@inheritDoc}
542
     */
543 2
    public function inNamespace()
544
    {
545 2
        return !empty($this->namespaceName);
546
    }
547
548
    /**
549
     * {@inheritDoc}
550
     */
551 2
    public function isAbstract()
552
    {
553 2
        if ($this->classLikeNode instanceof Class_ && $this->classLikeNode->isAbstract()) {
554 1
            return true;
555 2
        } elseif ($this->isInterface() && !empty($this->getMethods())) {
556 1
            return true;
557 2
        } elseif ($this->isTrait()) {
558 1
            return true;
559
        }
560
561 2
        return false;
562
    }
563
564
    /**
565
     * Currently, anonymous classes aren't supported for parsed reflection
566
     */
567
    public function isAnonymous()
568
    {
569
        return false;
570
    }
571
572
    /**
573
     * {@inheritDoc}
574
     */
575 2
    public function isCloneable()
576
    {
577 2
        if ($this->isInterface() || $this->isAbstract()) {
578 1
            return false;
579
        }
580
581 2
        if ($this->hasMethod('__clone')) {
582 1
            return $this->getMethod('__clone')->isPublic();
583
        }
584
585 2
        return true;
586
    }
587
588
    /**
589
     * {@inheritDoc}
590
     */
591 2
    public function isFinal()
592
    {
593 2
        $isFinal = $this->classLikeNode instanceof Class_ && $this->classLikeNode->isFinal();
594
595 2
        return $isFinal;
596
    }
597
598
    /**
599
     * {@inheritDoc}
600
     */
601
    public function isInstance($object)
602
    {
603
        if (!is_object($object)) {
604
            throw new \RuntimeException(sprintf('Parameter must be an object, "%s" provided.', gettype($object)));
605
        }
606
607
        $className = $this->getName();
608
609
        return $className === get_class($object) || is_subclass_of($object, $className);
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $className can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
610
    }
611
612
    /**
613
     * {@inheritDoc}
614
     */
615 2
    public function isInstantiable()
616
    {
617 2
        if ($this->isInterface() || $this->isAbstract()) {
618 1
            return false;
619
        }
620
621 2
        if (null === ($constructor = $this->getConstructor())) {
622 2
            return true;
623
        }
624
625 1
        return $constructor->isPublic();
626
    }
627
628
    /**
629
     * {@inheritDoc}
630
     */
631 2
    public function isInterface()
632
    {
633 2
        return ($this->classLikeNode instanceof Interface_);
634
    }
635
636
    /**
637
     * {@inheritDoc}
638
     */
639 2
    public function isInternal()
640
    {
641
        // never can be an internal method
642 2
        return false;
643
    }
644
645
    /**
646
     * {@inheritDoc}
647
     */
648 2
    public function isIterateable()
649
    {
650 2
        return $this->implementsInterface('Traversable');
651
    }
652
653
    /**
654
     * {@inheritDoc}
655
     */
656
    public function isSubclassOf($class)
657
    {
658
        if (is_object($class)) {
659
            if ($class instanceof ReflectionClass) {
660
                $class = $class->name;
661
            } else {
662
                $class = get_class($class);
663
            }
664
        }
665
666
        if (!$this->classLikeNode instanceof Class_) {
667
            return false;
668
        } else {
669
            $extends = $this->classLikeNode->extends;
670
            if ($extends && $extends->toString() == $class) {
671
                return true;
672
            }
673
        }
674
675
        $parent = $this->getParentClass();
676
677
        return false === $parent ? false : $parent->isSubclassOf($class);
678
    }
679
680
    /**
681
     * {@inheritDoc}
682
     */
683 2
    public function isTrait()
684
    {
685 2
        return ($this->classLikeNode instanceof Trait_);
686
    }
687
688
    /**
689
     * {@inheritDoc}
690
     */
691 2
    public function isUserDefined()
692
    {
693
        // always defined by user, because we parse the source code
694 2
        return true;
695
    }
696
697
    /**
698
     * Gets static properties
699
     *
700
     * @link http://php.net/manual/en/reflectionclass.getstaticproperties.php
701
     *
702
     * @return array
703
     */
704 3
    public function getStaticProperties()
705
    {
706
        // In runtime static properties can be changed in any time
707 3
        if ($this->isInitialized()) {
708 1
            return forward_static_call('parent::getStaticProperties');
709
        }
710
711 2
        $properties = [];
712
713 2
        $reflectionProperties = $this->getProperties(ReflectionProperty::IS_STATIC);
714 2
        foreach ($reflectionProperties as $reflectionProperty) {
715 1
            if (!$reflectionProperty instanceof ReflectionProperty) {
716 1
                if (!$reflectionProperty->isPublic()) {
717 1
                    $reflectionProperty->setAccessible(true);
718 1
                }
719 1
            }
720 1
            $properties[$reflectionProperty->getName()] = $reflectionProperty->getValue();
721 2
        }
722
723 2
        return $properties;
724
    }
725
726
    /**
727
     * Gets static property value
728
     *
729
     * @param string $name    The name of the static property for which to return a value.
730
     * @param mixed  $default A default value to return in case the class does not declare
731
     *                        a static property with the given name
732
     *
733
     * @return mixed
734
     * @throws ReflectionException If there is no such property and no default value was given
735
     */
736 1
    public function getStaticPropertyValue($name, $default = null)
737
    {
738 1
        $properties     = $this->getStaticProperties();
739 1
        $propertyExists = array_key_exists($name, $properties);
740
741 1
        if (!$propertyExists && func_num_args() === 1) {
742
            throw new ReflectionException("Static property does not exist and no default value is given");
743
        }
744
745 1
        return $propertyExists ? $properties[$name] : $default;
746
    }
747
748
749
    /**
750
     * Creates a new class instance from given arguments.
751
     *
752
     * @link http://php.net/manual/en/reflectionclass.newinstance.php
753
     * @param mixed $args Accepts a variable number of arguments which are passed to the class constructor
754
     *
755
     * @return object
756
     */
757 1
    public function newInstance($args = null)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
758
    {
759 1
        $this->initializeInternalReflection();
760
761 1
        return call_user_func_array('parent::newInstance', func_get_args());
762
    }
763
764
    /**
765
     * Creates a new class instance from given arguments.
766
     *
767
     * @link http://php.net/manual/en/reflectionclass.newinstanceargs.php
768
     *
769
     * @param array $args The parameters to be passed to the class constructor as an array.
770
     *
771
     * @return object
772
     */
773 1
    public function newInstanceArgs(array $args = [])
774
    {
775 1
        $function = __FUNCTION__;
776 1
        $this->initializeInternalReflection();
777
778 1
        return parent::$function($args);
779
    }
780
781
    /**
782
     * Creates a new class instance without invoking the constructor.
783
     *
784
     * @link http://php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php
785
     *
786
     * @return object
787
     */
788 1
    public function newInstanceWithoutConstructor($args = null)
789
    {
790 1
        $function = __FUNCTION__;
791 1
        $this->initializeInternalReflection();
792
793 1
        return parent::$function($args);
794
    }
795
796
    /**
797
     * Sets static property value
798
     *
799
     * @link http://php.net/manual/en/reflectionclass.setstaticpropertyvalue.php
800
     *
801
     * @param string $name Property name
802
     * @param mixed $value New property value
803
     */
804 1
    public function setStaticPropertyValue($name, $value)
805
    {
806 1
        $this->initializeInternalReflection();
807
808 1
        forward_static_call('parent::setStaticPropertyValue', $name, $value);
809 1
    }
810
811 9
    private function recursiveCollect(\Closure $collector)
812
    {
813 9
        $result = array();
814
815 9
        $parentClass = $this->getParentClass();
816 9
        if ($parentClass) {
817 3
            $collector($result, $parentClass);
818 3
        }
819
820 9
        $interfaces = ReflectionClass::collectInterfacesFromClassNode($this->classLikeNode);
821 9
        foreach ($interfaces as $interface) {
822 1
            $collector($result, $interface);
823 9
        }
824
825 9
        return $result;
826
    }
827
828
    /**
829
     * Returns list of constants from the class
830
     *
831
     * @return array
832
     */
833 3
    private function findConstants()
834
    {
835 3
        $constants        = array();
836 3
        $expressionSolver = new NodeExpressionResolver($this);
837
838
        // constants can be only top-level nodes in the class, so we can scan them directly
839 3
        foreach ($this->classLikeNode->stmts as $classLevelNode) {
840 3
            if ($classLevelNode instanceof ClassConst) {
841 3
                $nodeConstants = $classLevelNode->consts;
842 3
                if (!empty($nodeConstants)) {
843 3
                    foreach ($nodeConstants as $nodeConstant) {
844 3
                        $expressionSolver->process($nodeConstant->value);
845 3
                        $constants[$nodeConstant->name] = $expressionSolver->getValue();
846 3
                    }
847 3
                }
848 3
            }
849 3
        }
850
851 3
        return $constants;
852
    }
853
}
854