1
|
|
|
<?php |
2
|
|
|
declare(strict_types=1); |
3
|
|
|
|
4
|
|
|
/** |
5
|
|
|
* This file is part of phpDocumentor. |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
* |
10
|
|
|
* @copyright 2010-2018 Mike van Riel<[email protected]> |
11
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php MIT |
12
|
|
|
* @link http://phpdoc.org |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
namespace phpDocumentor\Reflection\NodeVisitor; |
16
|
|
|
|
17
|
|
|
use phpDocumentor\Reflection\Fqsen; |
18
|
|
|
use PhpParser\Node; |
19
|
|
|
use PhpParser\Node\Const_; |
20
|
|
|
use PhpParser\Node\Stmt\Class_; |
21
|
|
|
use PhpParser\Node\Stmt\ClassConst; |
22
|
|
|
use PhpParser\Node\Stmt\ClassMethod; |
23
|
|
|
use PhpParser\Node\Stmt\Function_; |
24
|
|
|
use PhpParser\Node\Stmt\Interface_; |
25
|
|
|
use PhpParser\Node\Stmt\Namespace_; |
26
|
|
|
use PhpParser\Node\Stmt\PropertyProperty; |
27
|
|
|
use PhpParser\Node\Stmt\Trait_; |
28
|
|
|
use PhpParser\NodeTraverser; |
29
|
|
|
use PhpParser\NodeVisitorAbstract; |
30
|
|
|
use SplDoublyLinkedList; |
31
|
|
|
|
32
|
|
|
final class ElementNameResolver extends NodeVisitorAbstract |
33
|
|
|
{ |
34
|
|
|
/** |
35
|
|
|
* @var SplDoublyLinkedList |
36
|
|
|
*/ |
37
|
|
|
private $parts = null; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Resets the object to a known state before start processing. |
41
|
|
|
*/ |
42
|
|
|
public function beforeTraverse(array $nodes): void |
43
|
|
|
{ |
44
|
|
|
$this->resetState('\\'); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Performs a reset of the added element when needed. |
49
|
|
|
*/ |
50
|
1 |
|
public function leaveNode(Node $node): void |
51
|
|
|
{ |
52
|
1 |
|
switch (get_class($node)) { |
53
|
1 |
|
case Namespace_::class: |
54
|
1 |
|
case Class_::class: |
55
|
1 |
|
case ClassMethod::class: |
56
|
1 |
|
case Trait_::class: |
57
|
1 |
|
case PropertyProperty::class: |
58
|
1 |
|
case ClassConst::class: |
59
|
1 |
|
case Const_::class: |
60
|
1 |
|
case Interface_::class: |
61
|
1 |
|
case Function_::class: |
62
|
1 |
|
$this->parts->pop(); |
63
|
1 |
|
break; |
64
|
|
|
} |
65
|
1 |
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Adds fqsen property to a node when applicable. |
69
|
|
|
* |
70
|
|
|
* @todo this method is decorating the Node with an $fqsen property... |
71
|
|
|
* since we can't declare it in PhpParser/NodeAbstract, |
72
|
|
|
* we should add a decorator class wrapper in Reflection... |
73
|
|
|
* that should clear up the PHPSTAN errors about |
74
|
|
|
* "access to an undefined property ::$fqsen". |
75
|
|
|
*/ |
76
|
6 |
|
public function enterNode(Node $node): ?int |
77
|
|
|
{ |
78
|
6 |
|
switch (get_class($node)) { |
79
|
6 |
|
case Namespace_::class: |
|
|
|
|
80
|
2 |
|
$this->resetState('\\' . $node->name . '\\'); |
|
|
|
|
81
|
2 |
|
$node->fqsen = new Fqsen($this->buildName()); |
|
|
|
|
82
|
2 |
|
break; |
83
|
6 |
|
case Class_::class: |
84
|
4 |
|
case Trait_::class: |
85
|
4 |
|
case Interface_::class: |
86
|
4 |
|
$this->parts->push((string) $node->name); |
|
|
|
|
87
|
|
|
|
88
|
4 |
|
if (empty($node->name)) { |
|
|
|
|
89
|
2 |
|
return NodeTraverser::DONT_TRAVERSE_CHILDREN; |
90
|
|
|
} |
91
|
|
|
|
92
|
2 |
|
$node->fqsen = new Fqsen($this->buildName()); |
|
|
|
|
93
|
2 |
|
break; |
94
|
4 |
|
case Function_::class: |
95
|
1 |
|
$this->parts->push($node->name . '()'); |
|
|
|
|
96
|
1 |
|
$node->fqsen = new Fqsen($this->buildName()); |
|
|
|
|
97
|
1 |
|
break; |
98
|
3 |
|
case ClassMethod::class: |
99
|
|
|
$this->parts->push('::' . $node->name . '()'); |
|
|
|
|
100
|
|
|
$node->fqsen = new Fqsen($this->buildName()); |
|
|
|
|
101
|
|
|
break; |
102
|
3 |
|
case ClassConst::class: |
103
|
1 |
|
$this->parts->push('::'); |
104
|
1 |
|
break; |
105
|
3 |
|
case Const_::class: |
106
|
2 |
|
$this->parts->push($node->name); |
|
|
|
|
107
|
2 |
|
$node->fqsen = new Fqsen($this->buildName()); |
|
|
|
|
108
|
2 |
|
break; |
109
|
1 |
|
case PropertyProperty::class: |
110
|
|
|
$this->parts->push('::$' . $node->name); |
|
|
|
|
111
|
|
|
$node->fqsen = new Fqsen($this->buildName()); |
|
|
|
|
112
|
|
|
break; |
113
|
|
|
} |
114
|
|
|
|
115
|
5 |
|
return null; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Resets the state of the object to an empty state. |
120
|
|
|
*/ |
121
|
6 |
|
private function resetState(?string $namespace = null): void |
122
|
|
|
{ |
123
|
6 |
|
$this->parts = new SplDoublyLinkedList(); |
124
|
6 |
|
$this->parts->push($namespace); |
125
|
6 |
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Builds the name of the current node using the parts that are pushed to the parts list. |
129
|
|
|
*/ |
130
|
5 |
|
private function buildName(): string |
131
|
|
|
{ |
132
|
5 |
|
$name = null; |
133
|
5 |
|
foreach ($this->parts as $part) { |
134
|
5 |
|
$name .= $part; |
135
|
|
|
} |
136
|
|
|
|
137
|
5 |
|
return rtrim($name, '\\'); |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
|
As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next
break
.There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.