Completed
Pull Request — master (#82)
by Loren
05:32
created

ReflectionClass   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 94%

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 6
dl 0
loc 131
ccs 47
cts 50
cp 0.94
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 18 5
A isParsedNodeMissing() 0 12 3
B collectInterfacesFromClassNode() 0 19 6
B collectTraitsFromClassNode() 0 20 6
A ___debugInfo() 0 6 1
A getNode() 0 4 1
A __initialize() 0 4 1
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;
12
13
use Go\ParserReflection\Traits\InternalPropertiesEmulationTrait;
14
use Go\ParserReflection\Traits\ReflectionClassLikeTrait;
15
use PhpParser\Node\Name\FullyQualified;
16
use PhpParser\Node\Stmt\ClassLike;
17
use PhpParser\Node\Stmt\Interface_;
18
use PhpParser\Node\Stmt\TraitUse;
19
use ReflectionClass as BaseReflectionClass;
20
21
/**
22
 * AST-based reflection class
23
 */
24
class ReflectionClass extends BaseReflectionClass implements ReflectionInterface
25
{
26
    use ReflectionClassLikeTrait, InternalPropertiesEmulationTrait;
27
28
    /**
29
     * Initializes reflection instance
30
     *
31
     * @param string|object $argument Class name or instance of object
32
     * @param ClassLike $classLikeNode AST node for class
33
     */
34 8421
    public function __construct($argument, ClassLike $classLikeNode = null)
35
    {
36 8421
        $fullClassName       = is_object($argument) ? get_class($argument) : $argument;
37 8421
        $namespaceParts      = explode('\\', $fullClassName);
38 8421
        $this->className     = array_pop($namespaceParts);
39
        // Let's unset original read-only property to have a control over it via __get
40 8421
        unset($this->name);
41
42 8421
        $this->namespaceName = join('\\', $namespaceParts);
43
44 8421
        $this->classLikeNode = $classLikeNode;
45 8421
        if ($this->isParsedNodeMissing()) {
46 97
            $this->classLikeNode = ReflectionEngine::parseClass($fullClassName);
47
        }
48 8421
        if ($this->classLikeNode && ($this->className !== $this->classLikeNode->name)) {
49
            throw new \InvalidArgumentException("PhpParser\\Node\\Stmt\\ClassLike's name does not match provided class name.");
50
        }
51 8421
    }
52
53
    /**
54
     * Do we need to find the missing parser node?
55
     */
56 8421
    private function isParsedNodeMissing()
57
    {
58 8421
        if ($this->classLikeNode) {
59 8404
            return false;
60
        }
61 148
        $isUserDefined = true;
62 148
        if ($this->wasIncluded()) {
63 104
            $nativeRef = new BaseReflectionClass($this->getName());
64 104
            $isUserDefined = $nativeRef->isUserDefined();
65
        }
66 148
        return $isUserDefined;
67
    }
68
69
    /**
70
     * Parses interfaces from the concrete class node
71
     *
72
     * @param ClassLike $classLikeNode Class-like node
73
     *
74
     * @return array|\ReflectionClass[] List of reflections of interfaces
75
     */
76 463
    public static function collectInterfacesFromClassNode(ClassLike $classLikeNode)
77
    {
78 463
        $interfaces = [];
79
80 463
        $isInterface    = $classLikeNode instanceof Interface_;
81 463
        $interfaceField = $isInterface ? 'extends' : 'implements';
82 463
        $hasInterfaces  = in_array($interfaceField, $classLikeNode->getSubNodeNames());
83 463
        $implementsList = $hasInterfaces ? $classLikeNode->$interfaceField : array();
84 463
        if ($implementsList) {
85 14
            foreach ($implementsList as $implementNode) {
86 14
                if ($implementNode instanceof FullyQualified) {
87 14
                    $implementName              = $implementNode->toString();
88 14
                    $interfaces[$implementName] = new static($implementName);
89
                }
90
            }
91
        }
92
93 463
        return $interfaces;
94
    }
95
96
    /**
97
     * Parses traits from the concrete class node
98
     *
99
     * @param ClassLike $classLikeNode Class-like node
100
     * @param array     $traitAdaptations List of method adaptations
101
     *
102
     * @return array|\ReflectionClass[] List of reflections of traits
103
     */
104 313
    public static function collectTraitsFromClassNode(ClassLike $classLikeNode, array &$traitAdaptations)
105
    {
106 313
        $traits = [];
107
108 313
        if (!empty($classLikeNode->stmts)) {
109 274
            foreach ($classLikeNode->stmts as $classLevelNode) {
110 274
                if ($classLevelNode instanceof TraitUse) {
111 10
                    foreach ($classLevelNode->traits as $classTraitName) {
112 10
                        if ($classTraitName instanceof FullyQualified) {
113 10
                            $traitName          = $classTraitName->toString();
114 10
                            $traits[$traitName] = new static($traitName);
115
                        }
116
                    }
117 274
                    $traitAdaptations = $classLevelNode->adaptations;
118
                }
119
            }
120
        }
121
122 313
        return $traits;
123
    }
124
125
    /**
126
     * Emulating original behaviour of reflection
127
     */
128 157
    public function ___debugInfo()
129
    {
130
        return array(
131 157
            'name' => $this->getName()
132
        );
133
    }
134
135
    /**
136
     * Returns an AST-node for class
137
     *
138
     * @return ClassLike
139
     */
140
    public function getNode()
141
    {
142
        return $this->classLikeNode;
143
    }
144
145
    /**
146
     * Implementation of internal reflection initialization
147
     *
148
     * @return void
149
     */
150 94
    protected function __initialize()
151
    {
152 94
        parent::__construct($this->getName());
153 94
    }
154
}
155