Chris@17
|
1 <?php
|
Chris@17
|
2 /**
|
Chris@17
|
3 * A class to find T_VARIABLE tokens.
|
Chris@17
|
4 *
|
Chris@17
|
5 * This class can distinguish between normal T_VARIABLE tokens, and those tokens
|
Chris@17
|
6 * that represent class members. If a class member is encountered, then the
|
Chris@17
|
7 * processMemberVar method is called so the extending class can process it. If
|
Chris@17
|
8 * the token is found to be a normal T_VARIABLE token, then processVariable is
|
Chris@17
|
9 * called.
|
Chris@17
|
10 *
|
Chris@17
|
11 * @author Greg Sherwood <gsherwood@squiz.net>
|
Chris@17
|
12 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@17
|
13 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@17
|
14 */
|
Chris@17
|
15
|
Chris@17
|
16 namespace PHP_CodeSniffer\Sniffs;
|
Chris@17
|
17
|
Chris@17
|
18 use PHP_CodeSniffer\Files\File;
|
Chris@17
|
19 use PHP_CodeSniffer\Util\Tokens;
|
Chris@17
|
20
|
Chris@17
|
21 abstract class AbstractVariableSniff extends AbstractScopeSniff
|
Chris@17
|
22 {
|
Chris@17
|
23
|
Chris@17
|
24
|
Chris@17
|
25 /**
|
Chris@17
|
26 * List of PHP Reserved variables.
|
Chris@17
|
27 *
|
Chris@17
|
28 * Used by various naming convention sniffs.
|
Chris@17
|
29 *
|
Chris@17
|
30 * @var array
|
Chris@17
|
31 */
|
Chris@17
|
32 protected $phpReservedVars = [
|
Chris@17
|
33 '_SERVER' => true,
|
Chris@17
|
34 '_GET' => true,
|
Chris@17
|
35 '_POST' => true,
|
Chris@17
|
36 '_REQUEST' => true,
|
Chris@17
|
37 '_SESSION' => true,
|
Chris@17
|
38 '_ENV' => true,
|
Chris@17
|
39 '_COOKIE' => true,
|
Chris@17
|
40 '_FILES' => true,
|
Chris@17
|
41 'GLOBALS' => true,
|
Chris@17
|
42 'http_response_header' => true,
|
Chris@17
|
43 'HTTP_RAW_POST_DATA' => true,
|
Chris@17
|
44 'php_errormsg' => true,
|
Chris@17
|
45 ];
|
Chris@17
|
46
|
Chris@17
|
47
|
Chris@17
|
48 /**
|
Chris@17
|
49 * Constructs an AbstractVariableTest.
|
Chris@17
|
50 */
|
Chris@17
|
51 public function __construct()
|
Chris@17
|
52 {
|
Chris@17
|
53 $scopes = Tokens::$ooScopeTokens;
|
Chris@17
|
54
|
Chris@17
|
55 $listen = [
|
Chris@17
|
56 T_VARIABLE,
|
Chris@17
|
57 T_DOUBLE_QUOTED_STRING,
|
Chris@17
|
58 T_HEREDOC,
|
Chris@17
|
59 ];
|
Chris@17
|
60
|
Chris@17
|
61 parent::__construct($scopes, $listen, true);
|
Chris@17
|
62
|
Chris@17
|
63 }//end __construct()
|
Chris@17
|
64
|
Chris@17
|
65
|
Chris@17
|
66 /**
|
Chris@18
|
67 * Processes the token in the specified PHP_CodeSniffer\Files\File.
|
Chris@17
|
68 *
|
Chris@17
|
69 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
70 * token was found.
|
Chris@17
|
71 * @param int $stackPtr The position where the token was found.
|
Chris@17
|
72 * @param int $currScope The current scope opener token.
|
Chris@17
|
73 *
|
Chris@17
|
74 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
75 * called again on the current file until the returned stack
|
Chris@17
|
76 * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip
|
Chris@17
|
77 * the rest of the file.
|
Chris@17
|
78 */
|
Chris@17
|
79 final protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope)
|
Chris@17
|
80 {
|
Chris@17
|
81 $tokens = $phpcsFile->getTokens();
|
Chris@17
|
82
|
Chris@17
|
83 if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING
|
Chris@17
|
84 || $tokens[$stackPtr]['code'] === T_HEREDOC
|
Chris@17
|
85 ) {
|
Chris@17
|
86 // Check to see if this string has a variable in it.
|
Chris@17
|
87 $pattern = '|(?<!\\\\)(?:\\\\{2})*\${?[a-zA-Z0-9_]+}?|';
|
Chris@17
|
88 if (preg_match($pattern, $tokens[$stackPtr]['content']) !== 0) {
|
Chris@17
|
89 return $this->processVariableInString($phpcsFile, $stackPtr);
|
Chris@17
|
90 }
|
Chris@17
|
91
|
Chris@17
|
92 return;
|
Chris@17
|
93 }
|
Chris@17
|
94
|
Chris@18
|
95 // If this token is nested inside a function at a deeper
|
Chris@17
|
96 // level than the current OO scope that was found, it's a normal
|
Chris@17
|
97 // variable and not a member var.
|
Chris@17
|
98 $conditions = array_reverse($tokens[$stackPtr]['conditions'], true);
|
Chris@17
|
99 $inFunction = false;
|
Chris@17
|
100 foreach ($conditions as $scope => $code) {
|
Chris@17
|
101 if (isset(Tokens::$ooScopeTokens[$code]) === true) {
|
Chris@17
|
102 break;
|
Chris@17
|
103 }
|
Chris@17
|
104
|
Chris@17
|
105 if ($code === T_FUNCTION || $code === T_CLOSURE) {
|
Chris@17
|
106 $inFunction = true;
|
Chris@17
|
107 }
|
Chris@17
|
108 }
|
Chris@17
|
109
|
Chris@17
|
110 if ($scope !== $currScope) {
|
Chris@17
|
111 // We found a closer scope to this token, so ignore
|
Chris@17
|
112 // this particular time through the sniff. We will process
|
Chris@17
|
113 // this token when this closer scope is found to avoid
|
Chris@17
|
114 // duplicate checks.
|
Chris@17
|
115 return;
|
Chris@17
|
116 }
|
Chris@17
|
117
|
Chris@17
|
118 // Just make sure this isn't a variable in a function declaration.
|
Chris@17
|
119 if ($inFunction === false && isset($tokens[$stackPtr]['nested_parenthesis']) === true) {
|
Chris@17
|
120 foreach ($tokens[$stackPtr]['nested_parenthesis'] as $opener => $closer) {
|
Chris@17
|
121 if (isset($tokens[$opener]['parenthesis_owner']) === false) {
|
Chris@18
|
122 // Check if this is a USE statement for a closure.
|
Chris@17
|
123 $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), null, true);
|
Chris@17
|
124 if ($tokens[$prev]['code'] === T_USE) {
|
Chris@17
|
125 $inFunction = true;
|
Chris@17
|
126 break;
|
Chris@17
|
127 }
|
Chris@17
|
128
|
Chris@17
|
129 continue;
|
Chris@17
|
130 }
|
Chris@17
|
131
|
Chris@17
|
132 $owner = $tokens[$opener]['parenthesis_owner'];
|
Chris@17
|
133 if ($tokens[$owner]['code'] === T_FUNCTION
|
Chris@17
|
134 || $tokens[$owner]['code'] === T_CLOSURE
|
Chris@17
|
135 ) {
|
Chris@17
|
136 $inFunction = true;
|
Chris@17
|
137 break;
|
Chris@17
|
138 }
|
Chris@17
|
139 }
|
Chris@17
|
140 }//end if
|
Chris@17
|
141
|
Chris@17
|
142 if ($inFunction === true) {
|
Chris@17
|
143 return $this->processVariable($phpcsFile, $stackPtr);
|
Chris@17
|
144 } else {
|
Chris@17
|
145 return $this->processMemberVar($phpcsFile, $stackPtr);
|
Chris@17
|
146 }
|
Chris@17
|
147
|
Chris@17
|
148 }//end processTokenWithinScope()
|
Chris@17
|
149
|
Chris@17
|
150
|
Chris@17
|
151 /**
|
Chris@17
|
152 * Processes the token outside the scope in the file.
|
Chris@17
|
153 *
|
Chris@17
|
154 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
155 * token was found.
|
Chris@17
|
156 * @param int $stackPtr The position where the token was found.
|
Chris@17
|
157 *
|
Chris@17
|
158 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
159 * called again on the current file until the returned stack
|
Chris@17
|
160 * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip
|
Chris@17
|
161 * the rest of the file.
|
Chris@17
|
162 */
|
Chris@17
|
163 final protected function processTokenOutsideScope(File $phpcsFile, $stackPtr)
|
Chris@17
|
164 {
|
Chris@17
|
165 $tokens = $phpcsFile->getTokens();
|
Chris@17
|
166 // These variables are not member vars.
|
Chris@17
|
167 if ($tokens[$stackPtr]['code'] === T_VARIABLE) {
|
Chris@17
|
168 return $this->processVariable($phpcsFile, $stackPtr);
|
Chris@17
|
169 } else if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING
|
Chris@17
|
170 || $tokens[$stackPtr]['code'] === T_HEREDOC
|
Chris@17
|
171 ) {
|
Chris@17
|
172 // Check to see if this string has a variable in it.
|
Chris@17
|
173 $pattern = '|(?<!\\\\)(?:\\\\{2})*\${?[a-zA-Z0-9_]+}?|';
|
Chris@17
|
174 if (preg_match($pattern, $tokens[$stackPtr]['content']) !== 0) {
|
Chris@17
|
175 return $this->processVariableInString($phpcsFile, $stackPtr);
|
Chris@17
|
176 }
|
Chris@17
|
177 }
|
Chris@17
|
178
|
Chris@17
|
179 }//end processTokenOutsideScope()
|
Chris@17
|
180
|
Chris@17
|
181
|
Chris@17
|
182 /**
|
Chris@17
|
183 * Called to process class member vars.
|
Chris@17
|
184 *
|
Chris@17
|
185 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
186 * token was found.
|
Chris@17
|
187 * @param int $stackPtr The position where the token was found.
|
Chris@17
|
188 *
|
Chris@17
|
189 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
190 * called again on the current file until the returned stack
|
Chris@17
|
191 * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip
|
Chris@17
|
192 * the rest of the file.
|
Chris@17
|
193 */
|
Chris@17
|
194 abstract protected function processMemberVar(File $phpcsFile, $stackPtr);
|
Chris@17
|
195
|
Chris@17
|
196
|
Chris@17
|
197 /**
|
Chris@17
|
198 * Called to process normal member vars.
|
Chris@17
|
199 *
|
Chris@17
|
200 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
201 * token was found.
|
Chris@17
|
202 * @param int $stackPtr The position where the token was found.
|
Chris@17
|
203 *
|
Chris@17
|
204 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
205 * called again on the current file until the returned stack
|
Chris@17
|
206 * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip
|
Chris@17
|
207 * the rest of the file.
|
Chris@17
|
208 */
|
Chris@17
|
209 abstract protected function processVariable(File $phpcsFile, $stackPtr);
|
Chris@17
|
210
|
Chris@17
|
211
|
Chris@17
|
212 /**
|
Chris@17
|
213 * Called to process variables found in double quoted strings or heredocs.
|
Chris@17
|
214 *
|
Chris@17
|
215 * Note that there may be more than one variable in the string, which will
|
Chris@17
|
216 * result only in one call for the string or one call per line for heredocs.
|
Chris@17
|
217 *
|
Chris@17
|
218 * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this
|
Chris@17
|
219 * token was found.
|
Chris@17
|
220 * @param int $stackPtr The position where the double quoted
|
Chris@17
|
221 * string was found.
|
Chris@17
|
222 *
|
Chris@17
|
223 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
224 * called again on the current file until the returned stack
|
Chris@17
|
225 * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip
|
Chris@17
|
226 * the rest of the file.
|
Chris@17
|
227 */
|
Chris@17
|
228 abstract protected function processVariableInString(File $phpcsFile, $stackPtr);
|
Chris@17
|
229
|
Chris@17
|
230
|
Chris@17
|
231 }//end class
|