Completed
Push — master ( 5ecb26...a15224 )
by Alexander
10s
created

ReflectionClassLikeTrait::getDefaultProperties()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7.0796

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 15
cts 17
cp 0.8824
c 0
b 0
f 0
rs 6.7272
cc 7
eloc 17
nc 6
nop 0
crap 7.0796
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
use PhpParser\Node\Stmt\TraitUseAdaptation;
25
26
/**
27
 * General class-like reflection
28
 */
29
trait ReflectionClassLikeTrait
30
{
31
    use InitializationTrait;
32
33
    /**
34
     * @var ClassLike
35
     */
36
    protected $classLikeNode;
37
38
    /**
39
     * Short name of the class, without namespace
40
     *
41
     * @var string
42
     */
43
    protected $className;
44
45
    /**
46
     * List of all constants from the class
47
     *
48
     * @var array
49
     */
50
    protected $constants;
51
52
    /**
53
     * Interfaces, empty array or null if not initialized yet
54
     *
55
     * @var \ReflectionClass[]|array|null
56
     */
57
    protected $interfaceClasses;
58
59
    /**
60
     * List of traits, empty array or null if not initialized yet
61
     *
62
     * @var  \ReflectionClass[]|array|null
63
     */
64
    protected $traits;
65
66
    /**
67
     * Additional list of trait adaptations
68
     *
69
     * @var TraitUseAdaptation[]|array
70
     */
71
    protected $traitAdaptations;
72
73
    /**
74
     * @var array|ReflectionMethod[]
75
     */
76
    protected $methods;
77
78
    /**
79
     * Namespace name
80
     *
81
     * @var string
82
     */
83
    protected $namespaceName = '';
84
85
    /**
86
     * Parent class, or false if not present, null if uninitialized yet
87
     *
88
     * @var \ReflectionClass|false|null
89
     */
90
    protected $parentClass;
91
92
    /**
93
     * @var array|ReflectionProperty[]
94
     */
95
    protected $properties;
96
97
    /**
98
     * Returns the string representation of the ReflectionClass object.
99
     *
100
     * @return string
101
     */
102
    public function __toString()
103
    {
104
        $isObject = $this instanceof \ReflectionObject;
105
106
        $staticProperties = $staticMethods = $defaultProperties = $dynamicProperties = $methods = [];
107
108
        $format  = "%s [ <user> %sclass %s%s%s ] {\n";
109
        $format .= "  @@ %s %d-%d\n\n";
110
        $format .= "  - Constants [%d] {%s\n  }\n\n";
111
        $format .= "  - Static properties [%d] {%s\n  }\n\n";
112
        $format .= "  - Static methods [%d] {%s\n  }\n\n";
113
        $format .= "  - Properties [%d] {%s\n  }\n\n";
114
        $format .= ($isObject ? "  - Dynamic properties [%d] {%s\n  }\n\n" : '%s%s');
115
        $format .= "  - Methods [%d] {%s\n  }\n";
116
        $format .= "}\n";
117
118
        foreach ($this->getProperties() as $property) {
119
            if ($property->isStatic()) {
120
                $staticProperties[] = $property;
121
            } elseif ($property->isDefault()) {
122
                $defaultProperties[] = $property;
123
            } else {
124
                $dynamicProperties[] = $property;
125
            }
126
        }
127
128
        foreach ($this->getMethods() as $method) {
129
            if ($method->isStatic()) {
130
                $staticMethods[] = $method;
131
            } else {
132
                $methods[] = $method;
133
            }
134
        }
135
136
        $buildString = function (array $items, $indentLevel = 4) {
137
            if (!count($items)) {
138
                return '';
139
            }
140
            $indent = "\n" . str_repeat(' ', $indentLevel);
141
            return $indent . implode($indent, explode("\n", implode("\n", $items)));
142
        };
143
        $buildConstants = function (array $items, $indentLevel = 4) {
144
            $str = '';
145
            foreach ($items as $name => $value) {
146
                $str .= "\n" . str_repeat(' ', $indentLevel);
147
                $str .= sprintf(
148
                    'Constant [ %s %s ] { %s }',
149
                    gettype($value),
150
                    $name,
151
                    $value
152
                );
153
            }
154
            return $str;
155
        };
156
        $interfaceNames = $this->getInterfaceNames();
157
        $parentClass    = $this->getParentClass();
158
        $modifiers      = '';
159
        if ($this->isAbstract()) {
160
            $modifiers = 'abstract ';
161
        } elseif ($this->isFinal()) {
162
            $modifiers = 'final ';
163
        };
164
165
        $string = sprintf(
166
            $format,
167
            ($isObject ? 'Object of class' : 'Class'),
168
            $modifiers,
169
            $this->getName(),
170
            false !== $parentClass ? (' extends ' . $parentClass->getName()) : '',
171
            $interfaceNames ? (' implements ' . implode(', ', $interfaceNames)) : '',
172
            $this->getFileName(),
173
            $this->getStartLine(),
174
            $this->getEndLine(),
175
            count($this->getConstants()),
176
            $buildConstants($this->getConstants()),
177
            count($staticProperties),
178
            $buildString($staticProperties),
179
            count($staticMethods),
180
            $buildString($staticMethods),
181
            count($defaultProperties),
182
            $buildString($defaultProperties),
183
            $isObject ? count($dynamicProperties) : '',
184
            $isObject ? $buildString($dynamicProperties) : '',
185
            count($methods),
186
            $buildString($methods)
187
        );
188
189
        return $string;
190
    }
191
192
193
    /**
194
     * {@inheritDoc}
195
     */
196 9
    public function getConstant($name)
197
    {
198 9
        if ($this->hasConstant($name)) {
199 9
            return $this->constants[$name];
200
        }
201
202
        return false;
203
    }
204
205
    /**
206
     * {@inheritDoc}
207
     */
208 34
    public function getConstants()
209
    {
210 34
        if (!isset($this->constants)) {
211
            $this->constants = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance) {
212 10
                $result += $instance->getConstants();
213 34
            });
214 34
            $this->collectSelfConstants();
215
        }
216
217 34
        return $this->constants;
218
    }
219
220
    /**
221
     * {@inheritDoc}
222
     */
223 16
    public function getConstructor()
224
    {
225 16
        $constructor = $this->getMethod('__construct');
226 16
        if (!$constructor) {
227 14
            return null;
228
        }
229
230 2
        return $constructor;
231
    }
232
233
    /**
234
     * Gets default properties from a class (including inherited properties).
235
     *
236
     * @link http://php.net/manual/en/reflectionclass.getdefaultproperties.php
237
     *
238
     * @return array An array of default properties, with the key being the name of the property and the value being
239
     * the default value of the property or NULL if the property doesn't have a default value
240
     */
241 26
    public function getDefaultProperties()
242
    {
243 26
        $defaultValues = [];
244 26
        $properties    = $this->getProperties();
245 26
        $staticOrder   = [true, false];
246 26
        foreach ($staticOrder as $shouldBeStatic) {
247 26
            foreach ($properties as $property) {
248 7
                $isStaticProperty     = $property->isStatic();
249 7
                if ($shouldBeStatic !== $isStaticProperty) {
250 7
                    continue;
251
                }
252 7
                $propertyName         = $property->getName();
253 7
                $isInternalReflection = get_class($property) == \ReflectionProperty::class;
254
255 7
                if (!$isInternalReflection || $isStaticProperty) {
256 7
                    $defaultValues[$propertyName] = $property->getValue();
257
                } elseif (!$isStaticProperty) {
258
                    // Internal reflection and dynamic property
259
                    $classProperties = $property->getDeclaringClass()->getDefaultProperties();
260 26
                    $defaultValues[$propertyName] = $classProperties[$propertyName];
261
                }
262
            }
263
        }
264
265 26
        return $defaultValues;
266
    }
267
268
    /**
269
     * {@inheritDoc}
270
     */
271 26
    public function getDocComment()
272
    {
273 26
        $docComment = $this->classLikeNode->getDocComment();
274
275 26
        return $docComment ? $docComment->getText() : false;
276
    }
277
278 26
    public function getEndLine()
279
    {
280 26
        return $this->classLikeNode->getAttribute('endLine');
281
    }
282
283 26
    public function getExtension()
284
    {
285 26
        return null;
286
    }
287
288 26
    public function getExtensionName()
289
    {
290 26
        return false;
291
    }
292
293 18
    public function getFileName()
294
    {
295 18
        return $this->classLikeNode->getAttribute('fileName');
296
    }
297
298
    /**
299
     * {@inheritDoc}
300
     */
301 26
    public function getInterfaceNames()
302
    {
303 26
        return array_keys($this->getInterfaces());
304
    }
305
306
    /**
307
     * {@inheritDoc}
308
     */
309 52
    public function getInterfaces()
310
    {
311 52
        if (!isset($this->interfaceClasses)) {
312
            $this->interfaceClasses = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance) {
313 6
                if ($instance->isInterface()) {
314 1
                    $result[$instance->name] = $instance;
315
                }
316 6
                $result += $instance->getInterfaces();
317 26
            });
318
        }
319
320 52
        return $this->interfaceClasses;
321
    }
322
323
    /**
324
     * {@inheritdoc}
325
     */
326 1579
    public function getMethod($name)
327
    {
328 1579
        $methods = $this->getMethods();
329 1579
        foreach ($methods as $method) {
330 1570
            if ($method->getName() == $name) {
331 1570
                return $method;
332
            }
333
        }
334
335 14
        return false;
336
    }
337
338
    /**
339
     * Returns list of reflection methods
340
     *
341
     * @param null|integer $filter Optional filter
342
     *
343
     * @return array|\ReflectionMethod[]
344
     */
345 1604
    public function getMethods($filter = null)
346
    {
347 1604
        if (!isset($this->methods)) {
348 52
            $directMethods = ReflectionMethod::collectFromClassNode($this->classLikeNode, $this);
349
            $parentMethods = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance, $isParent) {
350 18
                $reflectionMethods = [];
351 18
                foreach ($instance->getMethods() as $reflectionMethod) {
352 12
                    if (!$isParent || !$reflectionMethod->isPrivate()) {
353 12
                        $reflectionMethods[$reflectionMethod->name] = $reflectionMethod;
354
                    }
355
                }
356 18
                $result += $reflectionMethods;
357 52
            });
358 52
            $methods = $directMethods + $parentMethods;
359
360 52
            $this->methods = $methods;
361
        }
362 1604
        if (!isset($filter)) {
363 1601
            return array_values($this->methods);
364
        }
365
366 4
        $methods = [];
367 4
        foreach ($this->methods as $method) {
368 3
            if (!($filter & $method->getModifiers())) {
369 3
                continue;
370
            }
371 2
            $methods[] = $method;
372
        }
373
374 4
        return $methods;
375
    }
376
377
    /**
378
     * Returns a bitfield of the access modifiers for this class.
379
     *
380
     * @link http://php.net/manual/en/reflectionclass.getmodifiers.php
381
     *
382
     * NB: this method is not fully compatible with original value because of hidden internal constants
383
     *
384
     * @return int
385
     */
386 3
    public function getModifiers()
387
    {
388 3
        $modifiers = 0;
389
390 3
        if ($this->isFinal()) {
391 1
            $modifiers += \ReflectionClass::IS_FINAL;
392
        }
393
394 3
        if (PHP_VERSION_ID < 70000 && $this->isTrait()) {
395
            $modifiers += \ReflectionClass::IS_EXPLICIT_ABSTRACT;
396
        }
397
398 3
        if ($this->classLikeNode instanceof Class_ && $this->classLikeNode->isAbstract()) {
399 1
            $modifiers += \ReflectionClass::IS_EXPLICIT_ABSTRACT;
400
        }
401
402 3
        if ($this->isInterface()) {
403 1
            $abstractMethods = $this->getMethods();
404
        } else {
405 3
            $abstractMethods = $this->getMethods(\ReflectionMethod::IS_ABSTRACT);
406
        }
407 3
        if (!empty($abstractMethods)) {
408 1
            $modifiers += \ReflectionClass::IS_IMPLICIT_ABSTRACT;
409
        }
410
411 3
        return $modifiers;
412
    }
413
414
    /**
415
     * {@inheritDoc}
416
     */
417 2457
    public function getName()
418
    {
419 2457
        $namespaceName = $this->namespaceName ? $this->namespaceName . '\\' : '';
420
421 2457
        return $namespaceName . $this->getShortName();
422
    }
423
424
    /**
425
     * {@inheritDoc}
426
     */
427 44
    public function getNamespaceName()
428
    {
429 44
        return $this->namespaceName;
430
    }
431
432
    /**
433
     * {@inheritDoc}
434
     */
435 196
    public function getParentClass()
436
    {
437 196
        if (!isset($this->parentClass)) {
438 79
            static $extendsField = 'extends';
439
440 79
            $parentClass = false;
441 79
            $hasExtends  = in_array($extendsField, $this->classLikeNode->getSubNodeNames());
442 79
            $extendsNode = $hasExtends ? $this->classLikeNode->$extendsField : null;
443 79
            if ($extendsNode instanceof FullyQualified) {
444 22
                $extendsName = $extendsNode->toString();
445 22
                $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...
446
            }
447 79
            $this->parentClass = $parentClass;
448
        }
449
450 196
        return $this->parentClass;
451
    }
452
453
    /**
454
     * Retrieves reflected properties.
455
     *
456
     * @param int $filter The optional filter, for filtering desired property types.
457
     *                    It's configured using the ReflectionProperty constants, and defaults to all property types.
458
     *
459
     * @return array|\Go\ParserReflection\ReflectionProperty[]
460
     */
461 310
    public function getProperties($filter = null)
462
    {
463 310
        if (!isset($this->properties)) {
464 39
            $directProperties = ReflectionProperty::collectFromClassNode($this->classLikeNode, $this->getName());
465 39
            $parentProperties = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance, $isParent) {
466 9
                $reflectionProperties = [];
467 9
                foreach ($instance->getProperties() as $reflectionProperty) {
468 3
                    if (!$isParent || !$reflectionProperty->isPrivate()) {
469 3
                        $reflectionProperties[$reflectionProperty->name] = $reflectionProperty;
470
                    }
471
                }
472 9
                $result += $reflectionProperties;
473 39
            });
474 39
            $properties = $directProperties + $parentProperties;
475
476 39
            $this->properties = $properties;
477
        }
478
479
        // Without filter we can just return the full list
480 310
        if (!isset($filter)) {
481 284
            return array_values($this->properties);
482
        }
483
484 26
        $properties = [];
485 26
        foreach ($this->properties as $property) {
486 7
            if (!($filter & $property->getModifiers())) {
487 5
                continue;
488
            }
489 5
            $properties[] = $property;
490
        }
491
492 26
        return $properties;
493
    }
494
495
    /**
496
     * {@inheritdoc}
497
     */
498 255
    public function getProperty($name)
499
    {
500 255
        $properties = $this->getProperties();
501 255
        foreach ($properties as $property) {
502 255
            if ($property->getName() == $name) {
503 255
                return $property;
504
            }
505
        }
506
507
        return false;
508
    }
509
510
    /**
511
     * {@inheritDoc}
512
     */
513 2457
    public function getShortName()
514
    {
515 2457
        return $this->className;
516
    }
517
518 26
    public function getStartLine()
519
    {
520 26
        return $this->classLikeNode->getAttribute('startLine');
521
    }
522
523
    /**
524
     * Returns an array of trait aliases
525
     *
526
     * @link http://php.net/manual/en/reflectionclass.gettraitaliases.php
527
     *
528
     * @return array|null an array with new method names in keys and original names (in the format "TraitName::original") in
529
     * values.
530
     */
531 29
    public function getTraitAliases()
532
    {
533 29
        $aliases = [];
534 29
        $traits  = $this->getTraits();
535 29
        foreach ($this->traitAdaptations as $adaptation) {
536
            if ($adaptation instanceof TraitUseAdaptation\Alias) {
537
                $methodName = $adaptation->method;
538
                $traitName  = null;
539
                foreach ($traits as $trait) {
540
                    if ($trait->hasMethod($methodName)) {
541
                        $traitName = $trait->getName();
542
                        break;
543
                    }
544
                }
545
                $aliases[$adaptation->newName] = $traitName . '::'. $methodName;
546
            }
547
        }
548
549 29
        return $aliases;
550
    }
551
552
    /**
553
     * Returns an array of names of traits used by this class
554
     *
555
     * @link http://php.net/manual/en/reflectionclass.gettraitnames.php
556
     *
557
     * @return array
558
     */
559 26
    public function getTraitNames()
560
    {
561 26
        return array_keys($this->getTraits());
562
    }
563
564
    /**
565
     * Returns an array of traits used by this class
566
     *
567
     * @link http://php.net/manual/en/reflectionclass.gettraits.php
568
     *
569
     * @return array|\ReflectionClass[]
570
     */
571 200
    public function getTraits()
572
    {
573 200
        if (!isset($this->traits)) {
574 79
            $traitAdaptations = [];
575 79
            $this->traits     = ReflectionClass::collectTraitsFromClassNode($this->classLikeNode, $traitAdaptations);
576 79
            $this->traitAdaptations = $traitAdaptations;
577
        }
578
579 200
        return $this->traits;
580
    }
581
582
    /**
583
     * {@inheritDoc}
584
     */
585 10
    public function hasConstant($name)
586
    {
587 10
        $constants   = $this->getConstants();
588 10
        $hasConstant = isset($constants[$name]) || array_key_exists($name, $constants);
589
590 10
        return $hasConstant;
591
    }
592
593
    /**
594
     * {@inheritdoc}
595
     */
596 17
    public function hasMethod($name)
597
    {
598 17
        $methods = $this->getMethods();
599 17
        foreach ($methods as $method) {
600 8
            if ($method->getName() == $name) {
601 8
                return true;
602
            }
603
        }
604
605 15
        return false;
606
    }
607
608
    /**
609
     * {@inheritdoc}
610
     */
611
    public function hasProperty($name)
612
    {
613
        $properties = $this->getProperties();
614
        foreach ($properties as $property) {
615
            if ($property->getName() == $name) {
616
                return true;
617
            }
618
        }
619
620
        return false;
621
    }
622
623
    /**
624
     * {@inheritDoc}
625
     */
626 26
    public function implementsInterface($interfaceName)
627
    {
628 26
        $allInterfaces = $this->getInterfaces();
629
630 26
        return isset($allInterfaces[$interfaceName]);
631
    }
632
633
    /**
634
     * {@inheritDoc}
635
     */
636 26
    public function inNamespace()
637
    {
638 26
        return !empty($this->namespaceName);
639
    }
640
641
    /**
642
     * {@inheritDoc}
643
     */
644 66
    public function isAbstract()
645
    {
646 66
        if ($this->classLikeNode instanceof Class_ && $this->classLikeNode->isAbstract()) {
647 12
            return true;
648 54
        } elseif ($this->isInterface() && !empty($this->getMethods())) {
649 2
            return true;
650 52
        } elseif ($this->isTrait()) {
651 3
            return PHP_VERSION_ID < 70000 ? true : false;
652
        }
653
654 49
        return false;
655
    }
656
657
    /**
658
     * Currently, anonymous classes aren't supported for parsed reflection
659
     */
660
    public function isAnonymous()
661
    {
662
        return false;
663
    }
664
665
    /**
666
     * {@inheritDoc}
667
     */
668 26
    public function isCloneable()
669
    {
670 26
        if ($this->isInterface() || $this->isTrait() || $this->isAbstract()) {
671 10
            return false;
672
        }
673
674 16
        if ($this->hasMethod('__clone')) {
675 1
            return $this->getMethod('__clone')->isPublic();
676
        }
677
678 15
        return true;
679
    }
680
681
    /**
682
     * {@inheritDoc}
683
     */
684 29
    public function isFinal()
685
    {
686 29
        $isFinal = $this->classLikeNode instanceof Class_ && $this->classLikeNode->isFinal();
687
688 29
        return $isFinal;
689
    }
690
691
    /**
692
     * {@inheritDoc}
693
     */
694
    public function isInstance($object)
695
    {
696
        if (!is_object($object)) {
697
            throw new \RuntimeException(sprintf('Parameter must be an object, "%s" provided.', gettype($object)));
698
        }
699
700
        $className = $this->getName();
701
702
        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...
703
    }
704
705
    /**
706
     * {@inheritDoc}
707
     */
708 26
    public function isInstantiable()
709
    {
710 26
        if ($this->isInterface() || $this->isTrait() || $this->isAbstract()) {
711 10
            return false;
712
        }
713
714 16
        if (null === ($constructor = $this->getConstructor())) {
715 14
            return true;
716
        }
717
718 2
        return $constructor->isPublic();
719
    }
720
721
    /**
722
     * {@inheritDoc}
723
     */
724 202
    public function isInterface()
725
    {
726 202
        return ($this->classLikeNode instanceof Interface_);
727
    }
728
729
    /**
730
     * {@inheritDoc}
731
     */
732 26
    public function isInternal()
733
    {
734
        // never can be an internal method
735 26
        return false;
736
    }
737
738
    /**
739
     * {@inheritDoc}
740
     */
741 26
    public function isIterateable()
742
    {
743 26
        return $this->implementsInterface('Traversable');
744
    }
745
746
    /**
747
     * {@inheritDoc}
748
     */
749
    public function isSubclassOf($class)
750
    {
751
        if (is_object($class)) {
752
            if ($class instanceof ReflectionClass) {
753
                $class = $class->name;
754
            } else {
755
                $class = get_class($class);
756
            }
757
        }
758
759
        if (!$this->classLikeNode instanceof Class_) {
760
            return false;
761
        } else {
762
            $extends = $this->classLikeNode->extends;
763
            if ($extends && $extends->toString() == $class) {
764
                return true;
765
            }
766
        }
767
768
        $parent = $this->getParentClass();
769
770
        return false === $parent ? false : $parent->isSubclassOf($class);
771
    }
772
773
    /**
774
     * {@inheritDoc}
775
     */
776 94
    public function isTrait()
777
    {
778 94
        return ($this->classLikeNode instanceof Trait_);
779
    }
780
781
    /**
782
     * {@inheritDoc}
783
     */
784 26
    public function isUserDefined()
785
    {
786
        // always defined by user, because we parse the source code
787 26
        return true;
788
    }
789
790
    /**
791
     * Gets static properties
792
     *
793
     * @link http://php.net/manual/en/reflectionclass.getstaticproperties.php
794
     *
795
     * @return array
796
     */
797 27
    public function getStaticProperties()
798
    {
799
        // In runtime static properties can be changed in any time
800 27
        if ($this->isInitialized()) {
801 1
            return forward_static_call('parent::getStaticProperties');
802
        }
803
804 26
        $properties = [];
805
806 26
        $reflectionProperties = $this->getProperties(ReflectionProperty::IS_STATIC);
807 26
        foreach ($reflectionProperties as $reflectionProperty) {
808 5
            if (!$reflectionProperty instanceof ReflectionProperty) {
809 1
                if (!$reflectionProperty->isPublic()) {
810 1
                    $reflectionProperty->setAccessible(true);
811
                }
812
            }
813 5
            $properties[$reflectionProperty->getName()] = $reflectionProperty->getValue();
814
        }
815
816 26
        return $properties;
817
    }
818
819
    /**
820
     * Gets static property value
821
     *
822
     * @param string $name    The name of the static property for which to return a value.
823
     * @param mixed  $default A default value to return in case the class does not declare
824
     *                        a static property with the given name
825
     *
826
     * @return mixed
827
     * @throws ReflectionException If there is no such property and no default value was given
828
     */
829 1
    public function getStaticPropertyValue($name, $default = null)
830
    {
831 1
        $properties     = $this->getStaticProperties();
832 1
        $propertyExists = array_key_exists($name, $properties);
833
834 1
        if (!$propertyExists && func_num_args() === 1) {
835
            throw new ReflectionException("Static property does not exist and no default value is given");
836
        }
837
838 1
        return $propertyExists ? $properties[$name] : $default;
839
    }
840
841
842
    /**
843
     * Creates a new class instance from given arguments.
844
     *
845
     * @link http://php.net/manual/en/reflectionclass.newinstance.php
846
     * @param mixed $args Accepts a variable number of arguments which are passed to the class constructor
847
     *
848
     * @return object
849
     */
850 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...
851
    {
852 1
        $this->initializeInternalReflection();
853
854 1
        return call_user_func_array('parent::newInstance', func_get_args());
855
    }
856
857
    /**
858
     * Creates a new class instance from given arguments.
859
     *
860
     * @link http://php.net/manual/en/reflectionclass.newinstanceargs.php
861
     *
862
     * @param array $args The parameters to be passed to the class constructor as an array.
863
     *
864
     * @return object
865
     */
866 1
    public function newInstanceArgs(array $args = [])
867
    {
868 1
        $function = __FUNCTION__;
869 1
        $this->initializeInternalReflection();
870
871 1
        return parent::$function($args);
872
    }
873
874
    /**
875
     * Creates a new class instance without invoking the constructor.
876
     *
877
     * @link http://php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php
878
     *
879
     * @return object
880
     */
881 1
    public function newInstanceWithoutConstructor($args = null)
882
    {
883 1
        $function = __FUNCTION__;
884 1
        $this->initializeInternalReflection();
885
886 1
        return parent::$function($args);
887
    }
888
889
    /**
890
     * Sets static property value
891
     *
892
     * @link http://php.net/manual/en/reflectionclass.setstaticpropertyvalue.php
893
     *
894
     * @param string $name Property name
895
     * @param mixed $value New property value
896
     */
897 1
    public function setStaticPropertyValue($name, $value)
898
    {
899 1
        $this->initializeInternalReflection();
900
901 1
        forward_static_call('parent::setStaticPropertyValue', $name, $value);
902 1
    }
903
904 148
    private function recursiveCollect(\Closure $collector)
905
    {
906 148
        $result   = [];
907 148
        $isParent = true;
908
909 148
        $traits = $this->getTraits();
910 148
        foreach ($traits as $trait) {
911 8
            $collector($result, $trait, !$isParent);
912
        }
913
914 148
        $parentClass = $this->getParentClass();
915 148
        if ($parentClass) {
916 33
            $collector($result, $parentClass, $isParent);
917
        }
918
919 148
        $interfaces = ReflectionClass::collectInterfacesFromClassNode($this->classLikeNode);
920 148
        foreach ($interfaces as $interface) {
921 7
            $collector($result, $interface, $isParent);
922
        }
923
924 148
        return $result;
925
    }
926
927
    /**
928
     * Collects list of constants from the class itself
929
     */
930 34
    private function collectSelfConstants()
931
    {
932 34
        $expressionSolver = new NodeExpressionResolver($this);
933 34
        $localConstants   = [];
934
935
        // constants can be only top-level nodes in the class, so we can scan them directly
936 34
        foreach ($this->classLikeNode->stmts as $classLevelNode) {
937 30
            if ($classLevelNode instanceof ClassConst) {
938 15
                $nodeConstants = $classLevelNode->consts;
939 15
                if (!empty($nodeConstants)) {
940 15
                    foreach ($nodeConstants as $nodeConstant) {
941 15
                        $expressionSolver->process($nodeConstant->value);
942 15
                        $localConstants[$nodeConstant->name] = $expressionSolver->getValue();
943 30
                        $this->constants = $localConstants + $this->constants;
944
                    }
945
                }
946
            }
947
        }
948 34
    }
949
}
950