Completed
Push — master ( c4d2d4...eae51e )
by Alexander
9s
created

src/Traits/ReflectionClassLikeTrait.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 37
    public function getConstants()
209
    {
210 37
        if (!isset($this->constants)) {
211
            $this->constants = $this->recursiveCollect(function (array &$result, \ReflectionClass $instance) {
212 10
                $result += $instance->getConstants();
213 37
            });
214 37
            $this->collectSelfConstants();
215
        }
216
217 37
        return $this->constants;
218
    }
219
220
    /**
221
     * {@inheritDoc}
222
     */
223 19
    public function getConstructor()
224
    {
225 19
        $constructor = $this->getMethod('__construct');
226 19
        if (!$constructor) {
227 17
            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 29
    public function getDefaultProperties()
242
    {
243 29
        $defaultValues = [];
244 29
        $properties    = $this->getProperties();
245 29
        $staticOrder   = [true, false];
246 29
        foreach ($staticOrder as $shouldBeStatic) {
247 29
            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 29
                    $defaultValues[$propertyName] = $classProperties[$propertyName];
261
                }
262
            }
263
        }
264
265 29
        return $defaultValues;
266
    }
267
268
    /**
269
     * {@inheritDoc}
270
     */
271 29
    public function getDocComment()
272
    {
273 29
        $docComment = $this->classLikeNode->getDocComment();
274
275 29
        return $docComment ? $docComment->getText() : false;
276
    }
277
278 29
    public function getEndLine()
279
    {
280 29
        return $this->classLikeNode->getAttribute('endLine');
281
    }
282
283 29
    public function getExtension()
284
    {
285 29
        return null;
286
    }
287
288 29
    public function getExtensionName()
289
    {
290 29
        return false;
291
    }
292
293 18
    public function getFileName()
294
    {
295 18
        return $this->classLikeNode->getAttribute('fileName');
296
    }
297
298
    /**
299
     * {@inheritDoc}
300
     */
301 29
    public function getInterfaceNames()
302
    {
303 29
        return array_keys($this->getInterfaces());
304
    }
305
306
    /**
307
     * {@inheritDoc}
308
     */
309 58
    public function getInterfaces()
310
    {
311 58
        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 29
            });
318
        }
319
320 58
        return $this->interfaceClasses;
321
    }
322
323
    /**
324
     * {@inheritdoc}
325
     */
326 2016
    public function getMethod($name)
327
    {
328 2016
        $methods = $this->getMethods();
329 2016
        foreach ($methods as $method) {
330 2007
            if ($method->getName() == $name) {
331 2007
                return $method;
332
            }
333
        }
334
335 17
        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 2046
    public function getMethods($filter = null)
346
    {
347 2046
        if (!isset($this->methods)) {
348 60
            $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 60
            });
358 60
            $methods = $directMethods + $parentMethods;
359
360 60
            $this->methods = $methods;
361
        }
362 2046
        if (!isset($filter)) {
363 2042
            return array_values($this->methods);
364
        }
365
366 5
        $methods = [];
367 5
        foreach ($this->methods as $method) {
368 4
            if (!($filter & $method->getModifiers())) {
369 4
                continue;
370
            }
371 2
            $methods[] = $method;
372
        }
373
374 5
        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 4
    public function getModifiers()
387
    {
388 4
        $modifiers = 0;
389
390 4
        if ($this->isFinal()) {
391 1
            $modifiers += \ReflectionClass::IS_FINAL;
392
        }
393
394 4
        if (PHP_VERSION_ID < 70000 && $this->isTrait()) {
395
            $modifiers += \ReflectionClass::IS_EXPLICIT_ABSTRACT;
396
        }
397
398 4
        if ($this->classLikeNode instanceof Class_ && $this->classLikeNode->isAbstract()) {
399 1
            $modifiers += \ReflectionClass::IS_EXPLICIT_ABSTRACT;
400
        }
401
402 4
        if ($this->isInterface()) {
403 1
            $abstractMethods = $this->getMethods();
404
        } else {
405 4
            $abstractMethods = $this->getMethods(\ReflectionMethod::IS_ABSTRACT);
406
        }
407 4
        if (!empty($abstractMethods)) {
408 1
            $modifiers += \ReflectionClass::IS_IMPLICIT_ABSTRACT;
409
        }
410
411 4
        return $modifiers;
412
    }
413
414
    /**
415
     * {@inheritDoc}
416
     */
417 2966
    public function getName()
418
    {
419 2966
        $namespaceName = $this->namespaceName ? $this->namespaceName . '\\' : '';
420
421 2966
        return $namespaceName . $this->getShortName();
422
    }
423
424
    /**
425
     * {@inheritDoc}
426
     */
427 47
    public function getNamespaceName()
428
    {
429 47
        return $this->namespaceName;
430
    }
431
432
    /**
433
     * {@inheritDoc}
434
     */
435 228
    public function getParentClass()
436
    {
437 228
        if (!isset($this->parentClass)) {
438 88
            static $extendsField = 'extends';
439
440 88
            $parentClass = false;
441 88
            $hasExtends  = in_array($extendsField, $this->classLikeNode->getSubNodeNames());
442 88
            $extendsNode = $hasExtends ? $this->classLikeNode->$extendsField : null;
443 88
            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
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 88
            $this->parentClass = $parentClass;
448
        }
449
450 228
        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 317
    public function getProperties($filter = null)
462
    {
463 317
        if (!isset($this->properties)) {
464 43
            $directProperties = ReflectionProperty::collectFromClassNode($this->classLikeNode, $this->getName());
465 43
            $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 43
            });
474 43
            $properties = $directProperties + $parentProperties;
475
476 43
            $this->properties = $properties;
477
        }
478
479
        // Without filter we can just return the full list
480 317
        if (!isset($filter)) {
481 288
            return array_values($this->properties);
482
        }
483
484 29
        $properties = [];
485 29
        foreach ($this->properties as $property) {
486 7
            if (!($filter & $property->getModifiers())) {
487 5
                continue;
488
            }
489 5
            $properties[] = $property;
490
        }
491
492 29
        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 2966
    public function getShortName()
514
    {
515 2966
        return $this->className;
516
    }
517
518 29
    public function getStartLine()
519
    {
520 29
        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 33
    public function getTraitAliases()
532
    {
533 33
        $aliases = [];
534 33
        $traits  = $this->getTraits();
535 33
        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 33
        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 29
    public function getTraitNames()
560
    {
561 29
        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 224
    public function getTraits()
572
    {
573 224
        if (!isset($this->traits)) {
574 88
            $traitAdaptations = [];
575 88
            $this->traits     = ReflectionClass::collectTraitsFromClassNode($this->classLikeNode, $traitAdaptations);
576 88
            $this->traitAdaptations = $traitAdaptations;
577
        }
578
579 224
        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 20
    public function hasMethod($name)
597
    {
598 20
        $methods = $this->getMethods();
599 20
        foreach ($methods as $method) {
600 11
            if ($method->getName() == $name) {
601 11
                return true;
602
            }
603
        }
604
605 18
        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 29
    public function implementsInterface($interfaceName)
627
    {
628 29
        $allInterfaces = $this->getInterfaces();
629
630 29
        return isset($allInterfaces[$interfaceName]);
631
    }
632
633
    /**
634
     * {@inheritDoc}
635
     */
636 29
    public function inNamespace()
637
    {
638 29
        return !empty($this->namespaceName);
639
    }
640
641
    /**
642
     * {@inheritDoc}
643
     */
644 75
    public function isAbstract()
645
    {
646 75
        if ($this->classLikeNode instanceof Class_ && $this->classLikeNode->isAbstract()) {
647 12
            return true;
648 63
        } elseif ($this->isInterface() && !empty($this->getMethods())) {
649 2
            return true;
650 61
        } elseif ($this->isTrait()) {
651 3
            return PHP_VERSION_ID < 70000 ? true : false;
652
        }
653
654 58
        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 29
    public function isCloneable()
669
    {
670 29
        if ($this->isInterface() || $this->isTrait() || $this->isAbstract()) {
671 10
            return false;
672
        }
673
674 19
        if ($this->hasMethod('__clone')) {
675 1
            return $this->getMethod('__clone')->isPublic();
676
        }
677
678 18
        return true;
679
    }
680
681
    /**
682
     * {@inheritDoc}
683
     */
684 33
    public function isFinal()
685
    {
686 33
        $isFinal = $this->classLikeNode instanceof Class_ && $this->classLikeNode->isFinal();
687
688 33
        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
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 29
    public function isInstantiable()
709
    {
710 29
        if ($this->isInterface() || $this->isTrait() || $this->isAbstract()) {
711 10
            return false;
712
        }
713
714 19
        if (null === ($constructor = $this->getConstructor())) {
715 17
            return true;
716
        }
717
718 2
        return $constructor->isPublic();
719
    }
720
721
    /**
722
     * {@inheritDoc}
723
     */
724 243
    public function isInterface()
725
    {
726 243
        return ($this->classLikeNode instanceof Interface_);
727
    }
728
729
    /**
730
     * {@inheritDoc}
731
     */
732 29
    public function isInternal()
733
    {
734
        // never can be an internal method
735 29
        return false;
736
    }
737
738
    /**
739
     * {@inheritDoc}
740
     */
741 29
    public function isIterateable()
742
    {
743 29
        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 106
    public function isTrait()
777
    {
778 106
        return ($this->classLikeNode instanceof Trait_);
779
    }
780
781
    /**
782
     * {@inheritDoc}
783
     */
784 29
    public function isUserDefined()
785
    {
786
        // always defined by user, because we parse the source code
787 29
        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 30
    public function getStaticProperties()
798
    {
799
        // In runtime static properties can be changed in any time
800 30
        if ($this->isInitialized()) {
801 1
            return forward_static_call('parent::getStaticProperties');
802
        }
803
804 29
        $properties = [];
805
806 29
        $reflectionProperties = $this->getProperties(ReflectionProperty::IS_STATIC);
807 29
        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 29
        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
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 166
    private function recursiveCollect(\Closure $collector)
905
    {
906 166
        $result   = [];
907 166
        $isParent = true;
908
909 166
        $traits = $this->getTraits();
910 166
        foreach ($traits as $trait) {
911 8
            $collector($result, $trait, !$isParent);
912
        }
913
914 166
        $parentClass = $this->getParentClass();
915 166
        if ($parentClass) {
916 33
            $collector($result, $parentClass, $isParent);
917
        }
918
919 166
        $interfaces = ReflectionClass::collectInterfacesFromClassNode($this->classLikeNode);
920 166
        foreach ($interfaces as $interface) {
921 7
            $collector($result, $interface, $isParent);
922
        }
923
924 166
        return $result;
925
    }
926
927
    /**
928
     * Collects list of constants from the class itself
929
     */
930 37
    private function collectSelfConstants()
931
    {
932 37
        $expressionSolver = new NodeExpressionResolver($this);
933 37
        $localConstants   = [];
934
935
        // constants can be only top-level nodes in the class, so we can scan them directly
936 37
        foreach ($this->classLikeNode->stmts as $classLevelNode) {
937 33
            if ($classLevelNode instanceof ClassConst) {
938 16
                $nodeConstants = $classLevelNode->consts;
939 16
                if (!empty($nodeConstants)) {
940 16
                    foreach ($nodeConstants as $nodeConstant) {
941 16
                        $expressionSolver->process($nodeConstant->value);
942 16
                        $localConstants[$nodeConstant->name] = $expressionSolver->getValue();
943 33
                        $this->constants = $localConstants + $this->constants;
944
                    }
945
                }
946
            }
947
        }
948 37
    }
949
}
950