1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* PHPCS cross-version compatibility helper class. |
4
|
|
|
* |
5
|
|
|
* @category PHP |
6
|
|
|
* @package PHPCompatibility |
7
|
|
|
* @author Juliette Reinders Folmer <[email protected]> |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
namespace PHPCompatibility; |
11
|
|
|
|
12
|
|
|
use PHP_CodeSniffer_File as File; |
13
|
|
|
use PHP_CodeSniffer_Tokens as Tokens; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* \PHPCompatibility\PHPCSHelper |
17
|
|
|
* |
18
|
|
|
* PHPCS cross-version compatibility helper class. |
19
|
|
|
* |
20
|
|
|
* A number of PHPCS classes were split up into several classes in PHPCS 3.x |
21
|
|
|
* Those classes cannot be aliased as they don't represent the same object. |
22
|
|
|
* This class provides helper methods for functions which were contained in |
23
|
|
|
* one of these classes and which are used within the PHPCompatibility library. |
24
|
|
|
* |
25
|
|
|
* @category PHP |
26
|
|
|
* @package PHPCompatibility |
27
|
|
|
* @author Juliette Reinders Folmer <[email protected]> |
28
|
|
|
*/ |
29
|
|
|
class PHPCSHelper |
30
|
|
|
{ |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Get the PHPCS version number. |
34
|
|
|
* |
35
|
|
|
* @return string |
36
|
|
|
*/ |
37
|
|
|
public static function getVersion() |
38
|
|
|
{ |
39
|
|
|
if (defined('\PHP_CodeSniffer\Config::VERSION')) { |
40
|
|
|
// PHPCS 3.x. |
41
|
|
|
return \PHP_CodeSniffer\Config::VERSION; |
42
|
|
|
} else { |
43
|
|
|
// PHPCS 2.x. |
44
|
|
|
return \PHP_CodeSniffer::VERSION; |
45
|
|
|
} |
46
|
|
|
} |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Pass config data to PHPCS. |
51
|
|
|
* |
52
|
|
|
* PHPCS cross-version compatibility helper. |
53
|
|
|
* |
54
|
|
|
* @param string $key The name of the config value. |
55
|
|
|
* @param string|null $value The value to set. If null, the config entry |
56
|
|
|
* is deleted, reverting it to the default value. |
57
|
|
|
* @param boolean $temp Set this config data temporarily for this script run. |
58
|
|
|
* This will not write the config data to the config file. |
59
|
|
|
* |
60
|
|
|
* @return void |
61
|
|
|
*/ |
62
|
|
|
public static function setConfigData($key, $value, $temp = false) |
63
|
|
|
{ |
64
|
|
|
if (method_exists('\PHP_CodeSniffer\Config', 'setConfigData')) { |
65
|
|
|
// PHPCS 3.x. |
66
|
|
|
\PHP_CodeSniffer\Config::setConfigData($key, $value, $temp); |
67
|
|
|
} else { |
68
|
|
|
// PHPCS 2.x. |
69
|
|
|
\PHP_CodeSniffer::setConfigData($key, $value, $temp); |
70
|
|
|
} |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Get the value of a single PHPCS config key. |
76
|
|
|
* |
77
|
|
|
* @param string $key The name of the config value. |
78
|
|
|
* |
79
|
|
|
* @return string|null |
80
|
|
|
*/ |
81
|
|
|
public static function getConfigData($key) |
82
|
|
|
{ |
83
|
|
|
if (method_exists('\PHP_CodeSniffer\Config', 'getConfigData')) { |
84
|
|
|
// PHPCS 3.x. |
85
|
|
|
return \PHP_CodeSniffer\Config::getConfigData($key); |
86
|
|
|
} else { |
87
|
|
|
// PHPCS 2.x. |
88
|
|
|
return \PHP_CodeSniffer::getConfigData($key); |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Get the value of a single PHPCS config key. |
95
|
|
|
* |
96
|
|
|
* This config key can be set in the `CodeSniffer.conf` file, on the |
97
|
|
|
* command-line or in a ruleset. |
98
|
|
|
* |
99
|
|
|
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned. |
100
|
|
|
* @param string $key The name of the config value. |
101
|
|
|
* |
102
|
|
|
* @return string|null |
103
|
|
|
*/ |
104
|
|
|
public static function getCommandLineData($phpcsFile, $key) |
105
|
|
|
{ |
106
|
|
|
if (class_exists('\PHP_CodeSniffer\Config')) { |
107
|
|
|
// PHPCS 3.x. |
108
|
|
|
$config = $phpcsFile->config; |
|
|
|
|
109
|
|
|
if (isset($config->{$key})) { |
110
|
|
|
return $config->{$key}; |
111
|
|
|
} |
112
|
|
|
} else { |
113
|
|
|
// PHPCS 2.x. |
114
|
|
|
$config = $phpcsFile->phpcs->cli->getCommandLineValues(); |
|
|
|
|
115
|
|
|
if (isset($config[$key])) { |
116
|
|
|
return $config[$key]; |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
return null; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Returns the position of the first non-whitespace token in a statement. |
126
|
|
|
* |
127
|
|
|
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File` |
128
|
|
|
* class and introduced in PHPCS 2.1.0 and improved in PHPCS 2.7.1. |
129
|
|
|
* |
130
|
|
|
* Once the minimum supported PHPCS version for this standard goes beyond |
131
|
|
|
* that, this method can be removed and calls to it replaced with |
132
|
|
|
* `$phpcsFile->findStartOfStatement($start, $ignore)` calls. |
133
|
|
|
* |
134
|
|
|
* Last synced with PHPCS version: PHPCS 3.3.2 at commit 6ad28354c04b364c3c71a34e4a18b629cc3b231e}} |
135
|
|
|
* |
136
|
|
|
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile. |
137
|
|
|
* @param int $start The position to start searching from in the token stack. |
138
|
|
|
* @param int|array $ignore Token types that should not be considered stop points. |
139
|
|
|
* |
140
|
|
|
* @return int |
141
|
|
|
*/ |
142
|
|
|
public static function findStartOfStatement(File $phpcsFile, $start, $ignore = null) |
143
|
|
|
{ |
144
|
|
|
if (version_compare(self::getVersion(), '2.7.1', '>=') === true) { |
145
|
|
|
return $phpcsFile->findStartOfStatement($start, $ignore); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
$tokens = $phpcsFile->getTokens(); |
149
|
|
|
$endTokens = Tokens::$blockOpeners; |
150
|
|
|
|
151
|
|
|
$endTokens[T_COLON] = true; |
152
|
|
|
$endTokens[T_COMMA] = true; |
153
|
|
|
$endTokens[T_DOUBLE_ARROW] = true; |
154
|
|
|
$endTokens[T_SEMICOLON] = true; |
155
|
|
|
$endTokens[T_OPEN_TAG] = true; |
156
|
|
|
$endTokens[T_CLOSE_TAG] = true; |
157
|
|
|
$endTokens[T_OPEN_SHORT_ARRAY] = true; |
158
|
|
|
|
159
|
|
View Code Duplication |
if ($ignore !== null) { |
|
|
|
|
160
|
|
|
$ignore = (array) $ignore; |
161
|
|
|
foreach ($ignore as $code) { |
162
|
|
|
if (isset($endTokens[$code]) === true) { |
163
|
|
|
unset($endTokens[$code]); |
164
|
|
|
} |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$lastNotEmpty = $start; |
169
|
|
|
|
170
|
|
|
for ($i = $start; $i >= 0; $i--) { |
171
|
|
|
if (isset($endTokens[$tokens[$i]['code']]) === true) { |
172
|
|
|
// Found the end of the previous statement. |
173
|
|
|
return $lastNotEmpty; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
if (isset($tokens[$i]['scope_opener']) === true |
177
|
|
|
&& $i === $tokens[$i]['scope_closer'] |
178
|
|
|
) { |
179
|
|
|
// Found the end of the previous scope block. |
180
|
|
|
return $lastNotEmpty; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
// Skip nested statements. |
184
|
|
View Code Duplication |
if (isset($tokens[$i]['bracket_opener']) === true |
|
|
|
|
185
|
|
|
&& $i === $tokens[$i]['bracket_closer'] |
186
|
|
|
) { |
187
|
|
|
$i = $tokens[$i]['bracket_opener']; |
188
|
|
|
} elseif (isset($tokens[$i]['parenthesis_opener']) === true |
189
|
|
|
&& $i === $tokens[$i]['parenthesis_closer'] |
190
|
|
|
) { |
191
|
|
|
$i = $tokens[$i]['parenthesis_opener']; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
View Code Duplication |
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false) { |
|
|
|
|
195
|
|
|
$lastNotEmpty = $i; |
196
|
|
|
} |
197
|
|
|
}//end for |
198
|
|
|
|
199
|
|
|
return 0; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
|
203
|
|
|
/** |
204
|
|
|
* Returns the position of the last non-whitespace token in a statement. |
205
|
|
|
* |
206
|
|
|
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File` |
207
|
|
|
* class and introduced in PHPCS 2.1.0 and improved in PHPCS 2.7.1 and 3.3.0. |
208
|
|
|
* |
209
|
|
|
* Once the minimum supported PHPCS version for this standard goes beyond |
210
|
|
|
* that, this method can be removed and calls to it replaced with |
211
|
|
|
* `$phpcsFile->findEndOfStatement($start, $ignore)` calls. |
212
|
|
|
* |
213
|
|
|
* Last synced with PHPCS version: PHPCS 3.3.0-alpha at commit f5d899dcb5c534a1c3cca34668624517856ba823}} |
214
|
|
|
* |
215
|
|
|
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile. |
216
|
|
|
* @param int $start The position to start searching from in the token stack. |
217
|
|
|
* @param int|array $ignore Token types that should not be considered stop points. |
218
|
|
|
* |
219
|
|
|
* @return int |
220
|
|
|
*/ |
221
|
|
|
public static function findEndOfStatement(\PHP_CodeSniffer_File $phpcsFile, $start, $ignore = null) |
222
|
|
|
{ |
223
|
|
|
if (version_compare(self::getVersion(), '3.3.0', '>=') === true) { |
224
|
|
|
return $phpcsFile->findEndOfStatement($start, $ignore); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
$tokens = $phpcsFile->getTokens(); |
228
|
|
|
$endTokens = array( |
229
|
|
|
T_COLON => true, |
230
|
|
|
T_COMMA => true, |
231
|
|
|
T_DOUBLE_ARROW => true, |
232
|
|
|
T_SEMICOLON => true, |
233
|
|
|
T_CLOSE_PARENTHESIS => true, |
234
|
|
|
T_CLOSE_SQUARE_BRACKET => true, |
235
|
|
|
T_CLOSE_CURLY_BRACKET => true, |
236
|
|
|
T_CLOSE_SHORT_ARRAY => true, |
237
|
|
|
T_OPEN_TAG => true, |
238
|
|
|
T_CLOSE_TAG => true, |
239
|
|
|
); |
240
|
|
|
|
241
|
|
View Code Duplication |
if ($ignore !== null) { |
|
|
|
|
242
|
|
|
$ignore = (array) $ignore; |
243
|
|
|
foreach ($ignore as $code) { |
244
|
|
|
if (isset($endTokens[$code]) === true) { |
245
|
|
|
unset($endTokens[$code]); |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
$lastNotEmpty = $start; |
251
|
|
|
|
252
|
|
|
for ($i = $start; $i < $phpcsFile->numTokens; $i++) { |
|
|
|
|
253
|
|
|
if ($i !== $start && isset($endTokens[$tokens[$i]['code']]) === true) { |
254
|
|
|
// Found the end of the statement. |
255
|
|
|
if ($tokens[$i]['code'] === T_CLOSE_PARENTHESIS |
256
|
|
|
|| $tokens[$i]['code'] === T_CLOSE_SQUARE_BRACKET |
257
|
|
|
|| $tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET |
258
|
|
|
|| $tokens[$i]['code'] === T_CLOSE_SHORT_ARRAY |
259
|
|
|
|| $tokens[$i]['code'] === T_OPEN_TAG |
260
|
|
|
|| $tokens[$i]['code'] === T_CLOSE_TAG |
261
|
|
|
) { |
262
|
|
|
return $lastNotEmpty; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
return $i; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
// Skip nested statements. |
269
|
|
|
if (isset($tokens[$i]['scope_closer']) === true |
270
|
|
|
&& ($i === $tokens[$i]['scope_opener'] |
271
|
|
|
|| $i === $tokens[$i]['scope_condition']) |
272
|
|
|
) { |
273
|
|
|
if ($i === $start && isset(Tokens::$scopeOpeners[$tokens[$i]['code']]) === true) { |
274
|
|
|
return $tokens[$i]['scope_closer']; |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
$i = $tokens[$i]['scope_closer']; |
278
|
|
|
} elseif (isset($tokens[$i]['bracket_closer']) === true |
279
|
|
|
&& $i === $tokens[$i]['bracket_opener'] |
280
|
|
|
) { |
281
|
|
|
$i = $tokens[$i]['bracket_closer']; |
282
|
|
|
} elseif (isset($tokens[$i]['parenthesis_closer']) === true |
283
|
|
|
&& $i === $tokens[$i]['parenthesis_opener'] |
284
|
|
|
) { |
285
|
|
|
$i = $tokens[$i]['parenthesis_closer']; |
286
|
|
|
} |
287
|
|
|
|
288
|
|
View Code Duplication |
if (isset(\PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$i]['code']]) === false) { |
|
|
|
|
289
|
|
|
$lastNotEmpty = $i; |
290
|
|
|
} |
291
|
|
|
}//end for |
292
|
|
|
|
293
|
|
|
return ($phpcsFile->numTokens - 1); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
|
297
|
|
|
/** |
298
|
|
|
* Returns the name of the class that the specified class extends |
299
|
|
|
* (works for classes, anonymous classes and interfaces). |
300
|
|
|
* |
301
|
|
|
* Returns FALSE on error or if there is no extended class name. |
302
|
|
|
* |
303
|
|
|
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File` |
304
|
|
|
* class, but with some improvements which have been introduced in |
305
|
|
|
* PHPCS 2.8.0. |
306
|
|
|
* {@link https://github.com/squizlabs/PHP_CodeSniffer/commit/0011d448119d4c568e3ac1f825ae78815bf2cc34}. |
307
|
|
|
* |
308
|
|
|
* Once the minimum supported PHPCS version for this standard goes beyond |
309
|
|
|
* that, this method can be removed and calls to it replaced with |
310
|
|
|
* `$phpcsFile->findExtendedClassName($stackPtr)` calls. |
311
|
|
|
* |
312
|
|
|
* Last synced with PHPCS version: PHPCS 3.1.0-alpha at commit a9efcc9b0703f3f9f4a900623d4e97128a6aafc6}} |
313
|
|
|
* |
314
|
|
|
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile. |
315
|
|
|
* @param int $stackPtr The position of the class token in the stack. |
316
|
|
|
* |
317
|
|
|
* @return string|false |
318
|
|
|
*/ |
319
|
|
|
public static function findExtendedClassName(\PHP_CodeSniffer_File $phpcsFile, $stackPtr) |
320
|
|
|
{ |
321
|
|
|
if (version_compare(self::getVersion(), '3.1.0', '>=') === true) { |
322
|
|
|
return $phpcsFile->findExtendedClassName($stackPtr); |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
$tokens = $phpcsFile->getTokens(); |
326
|
|
|
|
327
|
|
|
// Check for the existence of the token. |
328
|
|
|
if (isset($tokens[$stackPtr]) === false) { |
329
|
|
|
return false; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
View Code Duplication |
if ($tokens[$stackPtr]['code'] !== T_CLASS |
|
|
|
|
333
|
|
|
&& $tokens[$stackPtr]['type'] !== 'T_ANON_CLASS' |
334
|
|
|
&& $tokens[$stackPtr]['type'] !== 'T_INTERFACE' |
335
|
|
|
) { |
336
|
|
|
return false; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
if (isset($tokens[$stackPtr]['scope_closer']) === false) { |
340
|
|
|
return false; |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
$classCloserIndex = $tokens[$stackPtr]['scope_closer']; |
344
|
|
|
$extendsIndex = $phpcsFile->findNext(T_EXTENDS, $stackPtr, $classCloserIndex); |
345
|
|
|
if ($extendsIndex === false) { |
346
|
|
|
return false; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
$find = array( |
350
|
|
|
T_NS_SEPARATOR, |
351
|
|
|
T_STRING, |
352
|
|
|
T_WHITESPACE, |
353
|
|
|
); |
354
|
|
|
|
355
|
|
|
$end = $phpcsFile->findNext($find, ($extendsIndex + 1), $classCloserIndex, true); |
356
|
|
|
$name = $phpcsFile->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1)); |
357
|
|
|
$name = trim($name); |
358
|
|
|
|
359
|
|
|
if ($name === '') { |
360
|
|
|
return false; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
return $name; |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* Returns the name(s) of the interface(s) that the specified class implements. |
369
|
|
|
* |
370
|
|
|
* Returns FALSE on error or if there are no implemented interface names. |
371
|
|
|
* |
372
|
|
|
* {@internal Duplicate of same method as introduced in PHPCS 2.7. |
373
|
|
|
* This method also includes an improvement we use which was only introduced |
374
|
|
|
* in PHPCS 2.8.0, so only defer to upstream for higher versions. |
375
|
|
|
* Once the minimum supported PHPCS version for this sniff library goes beyond |
376
|
|
|
* that, this method can be removed and calls to it replaced with |
377
|
|
|
* `$phpcsFile->findImplementedInterfaceNames($stackPtr)` calls.}} |
378
|
|
|
* |
379
|
|
|
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned. |
380
|
|
|
* @param int $stackPtr The position of the class token. |
381
|
|
|
* |
382
|
|
|
* @return array|false |
383
|
|
|
*/ |
384
|
|
|
public static function findImplementedInterfaceNames(\PHP_CodeSniffer_File $phpcsFile, $stackPtr) |
385
|
|
|
{ |
386
|
|
|
if (version_compare(self::getVersion(), '2.7.1', '>') === true) { |
387
|
|
|
return $phpcsFile->findImplementedInterfaceNames($stackPtr); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
$tokens = $phpcsFile->getTokens(); |
391
|
|
|
|
392
|
|
|
// Check for the existence of the token. |
393
|
|
|
if (isset($tokens[$stackPtr]) === false) { |
394
|
|
|
return false; |
395
|
|
|
} |
396
|
|
|
|
397
|
|
|
if ($tokens[$stackPtr]['code'] !== T_CLASS |
398
|
|
|
&& $tokens[$stackPtr]['type'] !== 'T_ANON_CLASS' |
399
|
|
|
) { |
400
|
|
|
return false; |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
if (isset($tokens[$stackPtr]['scope_closer']) === false) { |
404
|
|
|
return false; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
$classOpenerIndex = $tokens[$stackPtr]['scope_opener']; |
408
|
|
|
$implementsIndex = $phpcsFile->findNext(T_IMPLEMENTS, $stackPtr, $classOpenerIndex); |
409
|
|
|
if ($implementsIndex === false) { |
410
|
|
|
return false; |
411
|
|
|
} |
412
|
|
|
|
413
|
|
|
$find = array( |
414
|
|
|
T_NS_SEPARATOR, |
415
|
|
|
T_STRING, |
416
|
|
|
T_WHITESPACE, |
417
|
|
|
T_COMMA, |
418
|
|
|
); |
419
|
|
|
|
420
|
|
|
$end = $phpcsFile->findNext($find, ($implementsIndex + 1), ($classOpenerIndex + 1), true); |
421
|
|
|
$name = $phpcsFile->getTokensAsString(($implementsIndex + 1), ($end - $implementsIndex - 1)); |
422
|
|
|
$name = trim($name); |
423
|
|
|
|
424
|
|
|
if ($name === '') { |
425
|
|
|
return false; |
426
|
|
|
} else { |
427
|
|
|
$names = explode(',', $name); |
428
|
|
|
$names = array_map('trim', $names); |
429
|
|
|
return $names; |
430
|
|
|
} |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
|
434
|
|
|
/** |
435
|
|
|
* Returns the method parameters for the specified function token. |
436
|
|
|
* |
437
|
|
|
* Each parameter is in the following format: |
438
|
|
|
* |
439
|
|
|
* <code> |
440
|
|
|
* 0 => array( |
441
|
|
|
* 'name' => '$var', // The variable name. |
442
|
|
|
* 'token' => integer, // The stack pointer to the variable name. |
443
|
|
|
* 'content' => string, // The full content of the variable definition. |
444
|
|
|
* 'pass_by_reference' => boolean, // Is the variable passed by reference? |
445
|
|
|
* 'variable_length' => boolean, // Is the param of variable length through use of `...` ? |
446
|
|
|
* 'type_hint' => string, // The type hint for the variable. |
447
|
|
|
* 'type_hint_token' => integer, // The stack pointer to the type hint |
448
|
|
|
* // or false if there is no type hint. |
449
|
|
|
* 'nullable_type' => boolean, // Is the variable using a nullable type? |
450
|
|
|
* ) |
451
|
|
|
* </code> |
452
|
|
|
* |
453
|
|
|
* Parameters with default values have an additional array index of |
454
|
|
|
* 'default' with the value of the default as a string. |
455
|
|
|
* |
456
|
|
|
* {@internal Duplicate of same method as contained in the `\PHP_CodeSniffer_File` |
457
|
|
|
* class. |
458
|
|
|
* |
459
|
|
|
* Last synced with PHPCS version: PHPCS 3.3.0-alpha at commit 53a28408d345044c0360c2c1b4a2aaebf4a3b8c9}} |
460
|
|
|
* |
461
|
|
|
* @param \PHP_CodeSniffer_File $phpcsFile Instance of phpcsFile. |
462
|
|
|
* @param int $stackPtr The position in the stack of the |
463
|
|
|
* function token to acquire the |
464
|
|
|
* parameters for. |
465
|
|
|
* |
466
|
|
|
* @return array|false |
467
|
|
|
* @throws \PHP_CodeSniffer_Exception If the specified $stackPtr is not of |
468
|
|
|
* type T_FUNCTION or T_CLOSURE. |
469
|
|
|
*/ |
470
|
|
|
public static function getMethodParameters(\PHP_CodeSniffer_File $phpcsFile, $stackPtr) |
471
|
|
|
{ |
472
|
|
|
if (version_compare(self::getVersion(), '3.3.0', '>=') === true) { |
473
|
|
|
return $phpcsFile->getMethodParameters($stackPtr); |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
$tokens = $phpcsFile->getTokens(); |
477
|
|
|
|
478
|
|
|
// Check for the existence of the token. |
479
|
|
|
if (isset($tokens[$stackPtr]) === false) { |
480
|
|
|
return false; |
481
|
|
|
} |
482
|
|
|
|
483
|
|
View Code Duplication |
if ($tokens[$stackPtr]['code'] !== T_FUNCTION |
|
|
|
|
484
|
|
|
&& $tokens[$stackPtr]['code'] !== T_CLOSURE |
485
|
|
|
) { |
486
|
|
|
throw new \PHP_CodeSniffer_Exception('$stackPtr must be of type T_FUNCTION or T_CLOSURE'); |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
$opener = $tokens[$stackPtr]['parenthesis_opener']; |
490
|
|
|
$closer = $tokens[$stackPtr]['parenthesis_closer']; |
491
|
|
|
|
492
|
|
|
$vars = array(); |
493
|
|
|
$currVar = null; |
494
|
|
|
$paramStart = ($opener + 1); |
495
|
|
|
$defaultStart = null; |
496
|
|
|
$paramCount = 0; |
497
|
|
|
$passByReference = false; |
498
|
|
|
$variableLength = false; |
499
|
|
|
$typeHint = ''; |
500
|
|
|
$typeHintToken = false; |
501
|
|
|
$nullableType = false; |
502
|
|
|
|
503
|
|
|
for ($i = $paramStart; $i <= $closer; $i++) { |
504
|
|
|
// Check to see if this token has a parenthesis or bracket opener. If it does |
505
|
|
|
// it's likely to be an array which might have arguments in it. This |
506
|
|
|
// could cause problems in our parsing below, so lets just skip to the |
507
|
|
|
// end of it. |
508
|
|
View Code Duplication |
if (isset($tokens[$i]['parenthesis_opener']) === true) { |
|
|
|
|
509
|
|
|
// Don't do this if it's the close parenthesis for the method. |
510
|
|
|
if ($i !== $tokens[$i]['parenthesis_closer']) { |
511
|
|
|
$i = ($tokens[$i]['parenthesis_closer'] + 1); |
512
|
|
|
} |
513
|
|
|
} |
514
|
|
|
|
515
|
|
View Code Duplication |
if (isset($tokens[$i]['bracket_opener']) === true) { |
|
|
|
|
516
|
|
|
// Don't do this if it's the close parenthesis for the method. |
517
|
|
|
if ($i !== $tokens[$i]['bracket_closer']) { |
518
|
|
|
$i = ($tokens[$i]['bracket_closer'] + 1); |
519
|
|
|
} |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
switch ($tokens[$i]['type']) { |
523
|
|
|
case 'T_BITWISE_AND': |
524
|
|
|
if ($defaultStart === null) { |
525
|
|
|
$passByReference = true; |
526
|
|
|
} |
527
|
|
|
break; |
528
|
|
|
case 'T_VARIABLE': |
529
|
|
|
$currVar = $i; |
530
|
|
|
break; |
531
|
|
|
case 'T_ELLIPSIS': |
532
|
|
|
$variableLength = true; |
533
|
|
|
break; |
534
|
|
|
case 'T_ARRAY_HINT': // Pre-PHPCS 3.3.0. |
535
|
|
|
case 'T_CALLABLE': |
536
|
|
|
if ($typeHintToken === false) { |
537
|
|
|
$typeHintToken = $i; |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
$typeHint .= $tokens[$i]['content']; |
541
|
|
|
break; |
542
|
|
|
case 'T_SELF': |
543
|
|
|
case 'T_PARENT': |
544
|
|
View Code Duplication |
case 'T_STATIC': |
|
|
|
|
545
|
|
|
// Self and parent are valid, static invalid, but was probably intended as type hint. |
546
|
|
|
if (isset($defaultStart) === false) { |
547
|
|
|
if ($typeHintToken === false) { |
548
|
|
|
$typeHintToken = $i; |
549
|
|
|
} |
550
|
|
|
|
551
|
|
|
$typeHint .= $tokens[$i]['content']; |
552
|
|
|
} |
553
|
|
|
break; |
554
|
|
|
case 'T_STRING': |
555
|
|
|
// This is a string, so it may be a type hint, but it could |
556
|
|
|
// also be a constant used as a default value. |
557
|
|
|
$prevComma = false; |
558
|
|
View Code Duplication |
for ($t = $i; $t >= $opener; $t--) { |
|
|
|
|
559
|
|
|
if ($tokens[$t]['code'] === T_COMMA) { |
560
|
|
|
$prevComma = $t; |
561
|
|
|
break; |
562
|
|
|
} |
563
|
|
|
} |
564
|
|
|
|
565
|
|
|
if ($prevComma !== false) { |
566
|
|
|
$nextEquals = false; |
567
|
|
View Code Duplication |
for ($t = $prevComma; $t < $i; $t++) { |
|
|
|
|
568
|
|
|
if ($tokens[$t]['code'] === T_EQUAL) { |
569
|
|
|
$nextEquals = $t; |
570
|
|
|
break; |
571
|
|
|
} |
572
|
|
|
} |
573
|
|
|
|
574
|
|
|
if ($nextEquals !== false) { |
575
|
|
|
break; |
576
|
|
|
} |
577
|
|
|
} |
578
|
|
|
|
579
|
|
|
if ($defaultStart === null) { |
580
|
|
|
if ($typeHintToken === false) { |
581
|
|
|
$typeHintToken = $i; |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
$typeHint .= $tokens[$i]['content']; |
585
|
|
|
} |
586
|
|
|
break; |
587
|
|
View Code Duplication |
case 'T_NS_SEPARATOR': |
|
|
|
|
588
|
|
|
// Part of a type hint or default value. |
589
|
|
|
if ($defaultStart === null) { |
590
|
|
|
if ($typeHintToken === false) { |
591
|
|
|
$typeHintToken = $i; |
592
|
|
|
} |
593
|
|
|
|
594
|
|
|
$typeHint .= $tokens[$i]['content']; |
595
|
|
|
} |
596
|
|
|
break; |
597
|
|
|
case 'T_NULLABLE': |
598
|
|
|
case 'T_INLINE_THEN': // Pre-PHPCS 2.8.0. |
599
|
|
|
if ($defaultStart === null) { |
600
|
|
|
$nullableType = true; |
601
|
|
|
$typeHint .= $tokens[$i]['content']; |
602
|
|
|
} |
603
|
|
|
break; |
604
|
|
|
case 'T_CLOSE_PARENTHESIS': |
605
|
|
|
case 'T_COMMA': |
606
|
|
|
// If it's null, then there must be no parameters for this |
607
|
|
|
// method. |
608
|
|
|
if ($currVar === null) { |
609
|
|
|
break; |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
$vars[$paramCount] = array(); |
613
|
|
|
$vars[$paramCount]['token'] = $currVar; |
614
|
|
|
$vars[$paramCount]['name'] = $tokens[$currVar]['content']; |
615
|
|
|
$vars[$paramCount]['content'] = trim($phpcsFile->getTokensAsString($paramStart, ($i - $paramStart))); |
616
|
|
|
|
617
|
|
|
if ($defaultStart !== null) { |
618
|
|
|
$vars[$paramCount]['default'] = trim( |
619
|
|
|
$phpcsFile->getTokensAsString( |
620
|
|
|
$defaultStart, |
621
|
|
|
($i - $defaultStart) |
622
|
|
|
) |
623
|
|
|
); |
624
|
|
|
} |
625
|
|
|
|
626
|
|
|
$vars[$paramCount]['pass_by_reference'] = $passByReference; |
627
|
|
|
$vars[$paramCount]['variable_length'] = $variableLength; |
628
|
|
|
$vars[$paramCount]['type_hint'] = $typeHint; |
629
|
|
|
$vars[$paramCount]['type_hint_token'] = $typeHintToken; |
630
|
|
|
$vars[$paramCount]['nullable_type'] = $nullableType; |
631
|
|
|
|
632
|
|
|
// Reset the vars, as we are about to process the next parameter. |
633
|
|
|
$defaultStart = null; |
634
|
|
|
$paramStart = ($i + 1); |
635
|
|
|
$passByReference = false; |
636
|
|
|
$variableLength = false; |
637
|
|
|
$typeHint = ''; |
638
|
|
|
$typeHintToken = false; |
639
|
|
|
$nullableType = false; |
640
|
|
|
|
641
|
|
|
$paramCount++; |
642
|
|
|
break; |
643
|
|
|
case 'T_EQUAL': |
644
|
|
|
$defaultStart = ($i + 1); |
645
|
|
|
break; |
646
|
|
|
}//end switch |
647
|
|
|
}//end for |
648
|
|
|
|
649
|
|
|
return $vars; |
650
|
|
|
} |
651
|
|
|
} |
652
|
|
|
|
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.