1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author Kévin Gomez https://github.com/K-Phoen <[email protected]> |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
namespace PHPSA\Analyzer\Pass\Statement; |
7
|
|
|
|
8
|
|
|
use PhpParser\Node\Stmt; |
9
|
|
|
use PhpParser\Node; |
10
|
|
|
use PHPSA\Analyzer\Helper\DefaultMetadataPassTrait; |
11
|
|
|
use PHPSA\Analyzer\Pass; |
12
|
|
|
use PHPSA\Context; |
13
|
|
|
|
14
|
|
|
class UnexpectedUseOfThis implements Pass\AnalyzerPassInterface |
15
|
|
|
{ |
16
|
|
|
use DefaultMetadataPassTrait; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* @param Node\Stmt $stmt |
20
|
|
|
* @param Context $context |
21
|
|
|
* @return bool |
22
|
|
|
*/ |
23
|
23 |
|
public function pass(Node\Stmt $stmt, Context $context) |
24
|
|
|
{ |
25
|
23 |
|
$result = false; |
26
|
|
|
|
27
|
23 |
|
if ($stmt instanceof Stmt\ClassMethod) { |
28
|
23 |
|
$result = $this->inspectClassMethodArguments($stmt, $context) || $result; |
29
|
23 |
|
} |
30
|
|
|
|
31
|
23 |
|
if ($stmt instanceof Stmt\TryCatch) { |
32
|
1 |
|
$result = $this->inspectTryCatch($stmt, $context) || $result; |
33
|
1 |
|
} |
34
|
|
|
|
35
|
23 |
|
if ($stmt instanceof Stmt\Foreach_) { |
36
|
1 |
|
$result = $this->inspectForeach($stmt, $context) || $result; |
37
|
1 |
|
} |
38
|
|
|
|
39
|
23 |
|
if ($stmt instanceof Stmt\Static_) { |
40
|
1 |
|
$result = $this->inspectStaticVar($stmt, $context) || $result; |
41
|
1 |
|
} |
42
|
|
|
|
43
|
23 |
|
if ($stmt instanceof Stmt\Global_) { |
44
|
1 |
|
$result = $this->inspectGlobalVar($stmt, $context) || $result; |
45
|
1 |
|
} |
46
|
|
|
|
47
|
23 |
|
if ($stmt instanceof Stmt\Unset_) { |
48
|
1 |
|
$result = $this->inspectUnset($stmt, $context) || $result; |
49
|
1 |
|
} |
50
|
|
|
|
51
|
23 |
|
return $result; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @return array |
56
|
|
|
*/ |
57
|
1 |
|
public function getRegister() |
58
|
|
|
{ |
59
|
|
|
return [ |
60
|
1 |
|
Stmt\ClassMethod::class, |
61
|
1 |
|
Stmt\TryCatch::class, |
62
|
1 |
|
Stmt\Foreach_::class, |
63
|
1 |
|
Stmt\Static_::class, |
64
|
1 |
|
Stmt\Global_::class, |
65
|
1 |
|
Stmt\Unset_::class, |
66
|
1 |
|
]; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* @param Stmt\ClassMethod $methodStmt |
71
|
|
|
* @param Context $context |
72
|
|
|
* @return bool |
73
|
|
|
*/ |
74
|
23 |
|
private function inspectClassMethodArguments(Stmt\ClassMethod $methodStmt, Context $context) |
75
|
|
|
{ |
76
|
|
|
/** @var \PhpParser\Node\Param $param */ |
77
|
23 |
|
foreach ($methodStmt->getParams() as $param) { |
78
|
3 |
|
if ($param->name === 'this') { |
79
|
1 |
|
$context->notice( |
80
|
1 |
|
'unexpected_use.this', |
81
|
1 |
|
sprintf('Method %s can not have a parameter named "this".', $methodStmt->name), |
82
|
|
|
$param |
83
|
1 |
|
); |
84
|
|
|
|
85
|
1 |
|
return true; |
86
|
|
|
} |
87
|
23 |
|
} |
88
|
|
|
|
89
|
23 |
|
return false; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* @param Stmt\TryCatch $tryCatchStmt |
94
|
|
|
* @param Context $context |
95
|
|
|
* @return bool |
96
|
|
|
*/ |
97
|
1 |
|
private function inspectTryCatch(Stmt\TryCatch $tryCatchStmt, Context $context) |
98
|
|
|
{ |
99
|
1 |
|
$result = false; |
100
|
|
|
|
101
|
|
|
/** @var Stmt\Catch_ $catch */ |
102
|
1 |
|
foreach ($tryCatchStmt->catches as $catch) { |
103
|
1 |
|
if ($catch->var === 'this') { |
104
|
1 |
|
$result = true; |
105
|
1 |
|
$context->notice( |
106
|
1 |
|
'unexpected_use.this', |
107
|
1 |
|
'Catch block can not have a catch variable named "this".', |
108
|
|
|
$catch |
109
|
1 |
|
); |
110
|
1 |
|
} |
111
|
1 |
|
} |
112
|
|
|
|
113
|
1 |
|
return $result; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* @param Stmt\Foreach_ $foreachStmt |
118
|
|
|
* @param Context $context |
119
|
|
|
* @return bool |
120
|
|
|
*/ |
121
|
1 |
|
private function inspectForeach(Stmt\Foreach_ $foreachStmt, Context $context) |
122
|
|
|
{ |
123
|
1 |
|
if ($foreachStmt->valueVar->name === 'this') { |
|
|
|
|
124
|
1 |
|
$context->notice( |
125
|
1 |
|
'unexpected_use.this', |
126
|
1 |
|
'Foreach loop can not use a value variable named "this".', |
127
|
1 |
|
$foreachStmt->valueVar |
128
|
1 |
|
); |
129
|
|
|
|
130
|
1 |
|
return true; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
return false; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* @param Stmt\Static_ $staticStmt |
138
|
|
|
* @param Context $context |
139
|
|
|
* @return bool |
140
|
|
|
*/ |
141
|
1 |
|
private function inspectStaticVar(Stmt\Static_ $staticStmt, Context $context) |
142
|
|
|
{ |
143
|
1 |
|
$result = false; |
144
|
|
|
|
145
|
|
|
/** @var Stmt\StaticVar $var */ |
146
|
1 |
|
foreach ($staticStmt->vars as $var) { |
147
|
1 |
|
if ($var->name === 'this') { |
148
|
1 |
|
$result = true; |
149
|
|
|
|
150
|
1 |
|
$context->notice( |
151
|
1 |
|
'unexpected_use.this', |
152
|
1 |
|
'Can not declare a static variable named "this".', |
153
|
|
|
$var |
154
|
1 |
|
); |
155
|
1 |
|
} |
156
|
1 |
|
} |
157
|
|
|
|
158
|
1 |
|
return $result; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* @param Stmt\Global_ $globalStmt |
163
|
|
|
* @param Context $context |
164
|
|
|
* @return bool |
165
|
|
|
*/ |
166
|
1 |
|
private function inspectGlobalVar(Stmt\Global_ $globalStmt, Context $context) |
167
|
|
|
{ |
168
|
1 |
|
$result = false; |
169
|
|
|
|
170
|
1 |
|
foreach ($globalStmt->vars as $var) { |
171
|
1 |
|
if ($var->name === 'this') { |
|
|
|
|
172
|
1 |
|
$result = true; |
173
|
|
|
|
174
|
1 |
|
$context->notice( |
175
|
1 |
|
'unexpected_use.this', |
176
|
1 |
|
'Can not declare a global variable named "this".', |
177
|
|
|
$var |
178
|
1 |
|
); |
179
|
1 |
|
} |
180
|
1 |
|
} |
181
|
|
|
|
182
|
1 |
|
return $result; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* @param Stmt\Unset_ $unsetStmt |
187
|
|
|
* @param Context $context |
188
|
|
|
* @return bool |
189
|
|
|
*/ |
190
|
1 |
|
private function inspectUnset(Stmt\Unset_ $unsetStmt, Context $context) |
191
|
|
|
{ |
192
|
1 |
|
$result = false; |
193
|
|
|
|
194
|
1 |
|
foreach ($unsetStmt->vars as $var) { |
195
|
1 |
|
if ($var->name === 'this') { |
|
|
|
|
196
|
1 |
|
$result = true; |
197
|
|
|
|
198
|
1 |
|
$context->notice( |
199
|
1 |
|
'unexpected_use.this', |
200
|
1 |
|
'Can not unset $this.', |
201
|
|
|
$var |
202
|
1 |
|
); |
203
|
1 |
|
} |
204
|
1 |
|
} |
205
|
|
|
|
206
|
1 |
|
return $result; |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.