Completed
Pull Request — master (#25)
by Alexander
02:46
created

ReflectionFileNamespace::getClass()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2
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\ValueResolver\NodeExpressionResolver;
14
use PhpParser\Node\Stmt\ClassLike;
15
use PhpParser\Node\Stmt\Const_;
16
use PhpParser\Node\Stmt\Function_;
17
use PhpParser\Node\Stmt\Namespace_;
18
use PhpParser\Node\Stmt\Use_;
19
20
/**
21
 * AST-based reflection for the concrete namespace in the file
22
 */
23
class ReflectionFileNamespace
24
{
25
    /**
26
     * List of classes in the namespace
27
     *
28
     * @var array|ReflectionClass[]
29
     */
30
    protected $fileClasses;
31
32
    /**
33
     * List of functions in the namespace
34
     *
35
     * @var array|ReflectionFunction[]
36
     */
37
    protected $fileFunctions;
38
39
    /**
40
     * List of constants in the namespace
41
     *
42
     * @var array
43
     */
44
    protected $fileConstants;
45
46
    /**
47
     * List of imported namespaces (aliases)
48
     *
49
     * @var array
50
     */
51
    protected $fileNamespaceAliases;
52
53
    /**
54
     * Namespace node
55
     *
56
     * @var Namespace_
57
     */
58
    private $namespaceNode;
59
60
    /**
61
     * Name of the file
62
     *
63
     * @var string
64
     */
65
    private $fileName;
66
67
    /**
68
     * File namespace constructor
69
     *
70
     * @param string          $fileName      Name of the file
71
     * @param string          $namespaceName Name of the namespace
72
     * @param Namespace_|null $namespaceNode Optional AST-node for this namespace block
73
     */
74 136
    public function __construct($fileName, $namespaceName, Namespace_ $namespaceNode = null)
75
    {
76 136
        if (!$namespaceNode) {
77 13
            $namespaceNode = ReflectionEngine::parseFileNamespace($fileName, $namespaceName);
78
        }
79 136
        $this->namespaceNode = $namespaceNode;
80 136
        $this->fileName      = $fileName;
81 136
    }
82
83
    /**
84
     * Returns the concrete class from the file namespace or false if there is no class
85
     *
86
     * @param string $className
87
     *
88
     * @return bool|ReflectionClass
89
     */
90 105
    public function getClass($className)
91
    {
92 105
        if ($this->hasClass($className)) {
93 105
            return $this->fileClasses[$className];
94
        }
95
96 1
        return false;
97
    }
98
99
    /**
100
     * Gets list of classes in the namespace
101
     *
102
     * @return ReflectionClass[]|array
103
     */
104 108
    public function getClasses()
105
    {
106 108
        if (!isset($this->fileClasses)) {
107 108
            $this->fileClasses = $this->findClasses();
108
        }
109
110 108
        return $this->fileClasses;
111
    }
112
113
    /**
114
     * Returns a value for the constant
115
     *
116
     * @param string $constantName name of the constant to fetch
117
     *
118
     * @return bool|mixed
119
     */
120 10
    public function getConstant($constantName)
121
    {
122 10
        if ($this->hasConstant($constantName)) {
123 10
            return $this->fileConstants[$constantName];
124
        }
125
126 1
        return false;
127
    }
128
129
    /**
130
     * Returns a list of defined constants in the namespace
131
     *
132
     * @return array
133
     */
134 15
    public function getConstants()
135
    {
136 15
        if (!isset($this->fileConstants)) {
137 15
            $this->fileConstants = $this->findConstants();
138
        }
139
140 15
        return $this->fileConstants;
141
    }
142
143
    /**
144
     * Gets doc comments from a class.
145
     *
146
     * @return string|false The doc comment if it exists, otherwise "false"
147
     */
148 1
    public function getDocComment()
149
    {
150 1
        $docComment = false;
151 1
        $comments   = $this->namespaceNode->getAttribute('comments');
152
153 1
        if ($comments) {
154 1
            $docComment = (string) $comments[0];
155
        }
156
157 1
        return $docComment;
158
    }
159
160
    /**
161
     * Gets starting line number
162
     *
163
     * @return integer
164
     */
165 1
    public function getEndLine()
166
    {
167 1
        return $this->namespaceNode->getAttribute('endLine');
168
    }
169
170
    /**
171
     * Returns the name of file
172
     *
173
     * @return string
174
     */
175 3
    public function getFileName()
176
    {
177 3
        return $this->fileName;
178
    }
179
180
    /**
181
     * Returns the concrete function from the file namespace or false if there is no function
182
     *
183
     * @param string $functionName
184
     *
185
     * @return bool|ReflectionFunction
186
     */
187 9
    public function getFunction($functionName)
188
    {
189 9
        if ($this->hasFunction($functionName)) {
190 9
            return $this->fileFunctions[$functionName];
191
        }
192
193 1
        return false;
194
    }
195
196
    /**
197
     * Gets list of functions in the namespace
198
     *
199
     * @return ReflectionFunction[]|array
200
     */
201 15
    public function getFunctions()
202
    {
203 15
        if (!isset($this->fileFunctions)) {
204 15
            $this->fileFunctions = $this->findFunctions();
205
        }
206
207 15
        return $this->fileFunctions;
208
    }
209
210
    /**
211
     * Gets namespace name
212
     *
213
     * @return string
214
     */
215 126
    public function getName()
216
    {
217 126
        $nameNode = $this->namespaceNode->name;
218
219 126
        return $nameNode ? $nameNode->toString() : '';
220
    }
221
222
    /**
223
     * Returns a list of namespace aliases
224
     *
225
     * @return array
226
     */
227 1
    public function getNamespaceAliases()
228
    {
229 1
        if (!isset($this->fileNamespaceAliases)) {
230 1
            $this->fileNamespaceAliases = $this->findNamespaceAliases();
231
        }
232
233 1
        return $this->fileNamespaceAliases;
234
    }
235
236
    /**
237
     * Gets starting line number
238
     *
239
     * @return integer
240
     */
241 1
    public function getStartLine()
242
    {
243 1
        return $this->namespaceNode->getAttribute('startLine');
244
    }
245
246
    /**
247
     * Checks if the given class is present in this filenamespace
248
     *
249
     * @param string $className
250
     *
251
     * @return bool
252
     */
253 106
    public function hasClass($className)
254
    {
255 106
        $classes = $this->getClasses();
256
257 106
        return isset($classes[$className]);
258
    }
259
260
    /**
261
     * Checks if the given constant is present in this filenamespace
262
     *
263
     * @param string $constantName
264
     *
265
     * @return bool
266
     */
267 15
    public function hasConstant($constantName)
268
    {
269 15
        $constants = $this->getConstants();
270
271 15
        return isset($constants[$constantName]);
272
    }
273
274
    /**
275
     * Checks if the given function is present in this filenamespace
276
     *
277
     * @param string $functionName
278
     *
279
     * @return bool
280
     */
281 10
    public function hasFunction($functionName)
282
    {
283 10
        $functions = $this->getFunctions();
284
285 10
        return isset($functions[$functionName]);
286
    }
287
288
    /**
289
     * Searches for classes in the given AST
290
     *
291
     * @return array|ReflectionClass[]
292
     */
293 108
    private function findClasses()
294
    {
295 108
        $classes       = array();
296 108
        $namespaceName = $this->getName();
297
        // classes can be only top-level nodes in the namespace, so we can scan them directly
298 108
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
299 108
            if ($namespaceLevelNode instanceof ClassLike) {
300 108
                $classShortName = $namespaceLevelNode->name;
301 108
                $className = $namespaceName ? $namespaceName .'\\' . $classShortName : $classShortName;
302
303 108
                $namespaceLevelNode->setAttribute('fileName', $this->fileName);
304 108
                $classes[$className] = new ReflectionClass($className, $namespaceLevelNode);
305
            }
306
        }
307
308 108
        return $classes;
309
    }
310
311
    /**
312
     * Searches for functions in the given AST
313
     *
314
     * @return array
315
     */
316 15
    private function findFunctions()
317
    {
318 15
        $functions     = array();
319 15
        $namespaceName = $this->getName();
320
321
        // functions can be only top-level nodes in the namespace, so we can scan them directly
322 15
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
323 15
            if ($namespaceLevelNode instanceof Function_) {
324 15
                $funcShortName = $namespaceLevelNode->name;
325 15
                $functionName  = $namespaceName ? $namespaceName .'\\' . $funcShortName : $funcShortName;
326
327 15
                $namespaceLevelNode->setAttribute('fileName', $this->fileName);
328 15
                $functions[$funcShortName] = new ReflectionFunction($functionName, $namespaceLevelNode);
329
            }
330
        }
331
332 15
        return $functions;
333
    }
334
335
    /**
336
     * Searches for constants in the given AST
337
     *
338
     * @return array
339
     */
340 15
    private function findConstants()
341
    {
342 15
        $constants        = array();
343 15
        $expressionSolver = new NodeExpressionResolver($this);
344
345
        // constants can be only top-level nodes in the namespace, so we can scan them directly
346 15
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
347 15
            if ($namespaceLevelNode instanceof Const_) {
348 13
                $nodeConstants = $namespaceLevelNode->consts;
349 13
                if (!empty($nodeConstants)) {
350 13
                    foreach ($nodeConstants as $nodeConstant) {
351 13
                        $expressionSolver->process($nodeConstant->value);
352 15
                        $constants[$nodeConstant->name] = $expressionSolver->getValue();
353
                    }
354
                }
355
            }
356
        }
357
358 15
        return $constants;
359
    }
360
361
    /**
362
     * Searchse for namespace aliases for the current block
363
     *
364
     * @return array
365
     */
366 1
    private function findNamespaceAliases()
367
    {
368 1
        $namespaceAliases = [];
369
370
        // aliases can be only top-level nodes in the namespace, so we can scan them directly
371 1
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
372 1
            if ($namespaceLevelNode instanceof Use_) {
373 1
                $useAliases = $namespaceLevelNode->uses;
374 1
                if (!empty($useAliases)) {
375 1
                    foreach ($useAliases as $useNode) {
376 1
                        $namespaceAliases[$useNode->name->toString()] = $useNode->alias;
377
                    }
378
                }
379
            }
380
        }
381
382 1
        return $namespaceAliases;
383
    }
384
}
385