Chris@17
|
1 <?php
|
Chris@17
|
2 /**
|
Chris@17
|
3 * Allows tests that extend this class to listen for tokens within a particular scope.
|
Chris@17
|
4 *
|
Chris@17
|
5 * Below is a test that listens to methods that exist only within classes:
|
Chris@17
|
6 * <code>
|
Chris@17
|
7 * class ClassScopeTest extends PHP_CodeSniffer_Standards_AbstractScopeSniff
|
Chris@17
|
8 * {
|
Chris@17
|
9 * public function __construct()
|
Chris@17
|
10 * {
|
Chris@17
|
11 * parent::__construct(array(T_CLASS), array(T_FUNCTION));
|
Chris@17
|
12 * }
|
Chris@17
|
13 *
|
Chris@17
|
14 * protected function processTokenWithinScope(\PHP_CodeSniffer\Files\File $phpcsFile, $stackPtr, $currScope)
|
Chris@17
|
15 * {
|
Chris@17
|
16 * $className = $phpcsFile->getDeclarationName($currScope);
|
Chris@17
|
17 * echo 'encountered a method within class '.$className;
|
Chris@17
|
18 * }
|
Chris@17
|
19 * }
|
Chris@17
|
20 * </code>
|
Chris@17
|
21 *
|
Chris@17
|
22 * @author Greg Sherwood <gsherwood@squiz.net>
|
Chris@17
|
23 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@17
|
24 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@17
|
25 */
|
Chris@17
|
26
|
Chris@17
|
27 namespace PHP_CodeSniffer\Sniffs;
|
Chris@17
|
28
|
Chris@17
|
29 use PHP_CodeSniffer\Files\File;
|
Chris@17
|
30 use PHP_CodeSniffer\Exceptions\RuntimeException;
|
Chris@17
|
31
|
Chris@17
|
32 abstract class AbstractScopeSniff implements Sniff
|
Chris@17
|
33 {
|
Chris@17
|
34
|
Chris@17
|
35 /**
|
Chris@17
|
36 * The token types that this test wishes to listen to within the scope.
|
Chris@17
|
37 *
|
Chris@17
|
38 * @var array
|
Chris@17
|
39 */
|
Chris@17
|
40 private $tokens = [];
|
Chris@17
|
41
|
Chris@17
|
42 /**
|
Chris@17
|
43 * The type of scope opener tokens that this test wishes to listen to.
|
Chris@17
|
44 *
|
Chris@17
|
45 * @var string
|
Chris@17
|
46 */
|
Chris@17
|
47 private $scopeTokens = [];
|
Chris@17
|
48
|
Chris@17
|
49 /**
|
Chris@17
|
50 * True if this test should fire on tokens outside of the scope.
|
Chris@17
|
51 *
|
Chris@17
|
52 * @var boolean
|
Chris@17
|
53 */
|
Chris@17
|
54 private $listenOutside = false;
|
Chris@17
|
55
|
Chris@17
|
56
|
Chris@17
|
57 /**
|
Chris@17
|
58 * Constructs a new AbstractScopeTest.
|
Chris@17
|
59 *
|
Chris@17
|
60 * @param array $scopeTokens The type of scope the test wishes to listen to.
|
Chris@17
|
61 * @param array $tokens The tokens that the test wishes to listen to
|
Chris@17
|
62 * within the scope.
|
Chris@17
|
63 * @param boolean $listenOutside If true this test will also alert the
|
Chris@17
|
64 * extending class when a token is found outside
|
Chris@17
|
65 * the scope, by calling the
|
Chris@17
|
66 * processTokenOutsideScope method.
|
Chris@17
|
67 *
|
Chris@17
|
68 * @see PHP_CodeSniffer.getValidScopeTokeners()
|
Chris@17
|
69 * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified tokens array is empty.
|
Chris@17
|
70 */
|
Chris@17
|
71 public function __construct(
|
Chris@17
|
72 array $scopeTokens,
|
Chris@17
|
73 array $tokens,
|
Chris@17
|
74 $listenOutside=false
|
Chris@17
|
75 ) {
|
Chris@17
|
76 if (empty($scopeTokens) === true) {
|
Chris@17
|
77 $error = 'The scope tokens list cannot be empty';
|
Chris@17
|
78 throw new RuntimeException($error);
|
Chris@17
|
79 }
|
Chris@17
|
80
|
Chris@17
|
81 if (empty($tokens) === true) {
|
Chris@17
|
82 $error = 'The tokens list cannot be empty';
|
Chris@17
|
83 throw new RuntimeException($error);
|
Chris@17
|
84 }
|
Chris@17
|
85
|
Chris@17
|
86 $invalidScopeTokens = array_intersect($scopeTokens, $tokens);
|
Chris@17
|
87 if (empty($invalidScopeTokens) === false) {
|
Chris@17
|
88 $invalid = implode(', ', $invalidScopeTokens);
|
Chris@17
|
89 $error = "Scope tokens [$invalid] can't be in the tokens array";
|
Chris@17
|
90 throw new RuntimeException($error);
|
Chris@17
|
91 }
|
Chris@17
|
92
|
Chris@17
|
93 $this->listenOutside = $listenOutside;
|
Chris@17
|
94 $this->scopeTokens = array_flip($scopeTokens);
|
Chris@17
|
95 $this->tokens = $tokens;
|
Chris@17
|
96
|
Chris@17
|
97 }//end __construct()
|
Chris@17
|
98
|
Chris@17
|
99
|
Chris@17
|
100 /**
|
Chris@17
|
101 * The method that is called to register the tokens this test wishes to
|
Chris@17
|
102 * listen to.
|
Chris@17
|
103 *
|
Chris@17
|
104 * DO NOT OVERRIDE THIS METHOD. Use the constructor of this class to register
|
Chris@17
|
105 * for the desired tokens and scope.
|
Chris@17
|
106 *
|
Chris@17
|
107 * @return int[]
|
Chris@17
|
108 * @see __constructor()
|
Chris@17
|
109 */
|
Chris@17
|
110 final public function register()
|
Chris@17
|
111 {
|
Chris@17
|
112 return $this->tokens;
|
Chris@17
|
113
|
Chris@17
|
114 }//end register()
|
Chris@17
|
115
|
Chris@17
|
116
|
Chris@17
|
117 /**
|
Chris@17
|
118 * Processes the tokens that this test is listening for.
|
Chris@17
|
119 *
|
Chris@17
|
120 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
|
Chris@17
|
121 * @param int $stackPtr The position in the stack where this
|
Chris@17
|
122 * token was found.
|
Chris@17
|
123 *
|
Chris@17
|
124 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
125 * called again on the current file until the returned stack
|
Chris@17
|
126 * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip
|
Chris@17
|
127 * the rest of the file.
|
Chris@17
|
128 * @see processTokenWithinScope()
|
Chris@17
|
129 */
|
Chris@17
|
130 final public function process(File $phpcsFile, $stackPtr)
|
Chris@17
|
131 {
|
Chris@17
|
132 $tokens = $phpcsFile->getTokens();
|
Chris@17
|
133
|
Chris@17
|
134 $foundScope = false;
|
Chris@17
|
135 $skipPtrs = [];
|
Chris@17
|
136 foreach ($tokens[$stackPtr]['conditions'] as $scope => $code) {
|
Chris@17
|
137 if (isset($this->scopeTokens[$code]) === true) {
|
Chris@17
|
138 $skipPtrs[] = $this->processTokenWithinScope($phpcsFile, $stackPtr, $scope);
|
Chris@17
|
139 $foundScope = true;
|
Chris@17
|
140 }
|
Chris@17
|
141 }
|
Chris@17
|
142
|
Chris@17
|
143 if ($this->listenOutside === true && $foundScope === false) {
|
Chris@17
|
144 $skipPtrs[] = $this->processTokenOutsideScope($phpcsFile, $stackPtr);
|
Chris@17
|
145 }
|
Chris@17
|
146
|
Chris@17
|
147 if (empty($skipPtrs) === false) {
|
Chris@17
|
148 return min($skipPtrs);
|
Chris@17
|
149 }
|
Chris@17
|
150
|
Chris@17
|
151 return;
|
Chris@17
|
152
|
Chris@17
|
153 }//end process()
|
Chris@17
|
154
|
Chris@17
|
155
|
Chris@17
|
156 /**
|
Chris@17
|
157 * Processes a token that is found within the scope that this test is
|
Chris@17
|
158 * listening to.
|
Chris@17
|
159 *
|
Chris@17
|
160 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
|
Chris@17
|
161 * @param int $stackPtr The position in the stack where this
|
Chris@17
|
162 * token was found.
|
Chris@17
|
163 * @param int $currScope The position in the tokens array that
|
Chris@17
|
164 * opened the scope that this test is
|
Chris@17
|
165 * listening for.
|
Chris@17
|
166 *
|
Chris@17
|
167 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
168 * called again on the current file until the returned stack
|
Chris@17
|
169 * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip
|
Chris@17
|
170 * the rest of the file.
|
Chris@17
|
171 */
|
Chris@17
|
172 abstract protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope);
|
Chris@17
|
173
|
Chris@17
|
174
|
Chris@17
|
175 /**
|
Chris@17
|
176 * Processes a token that is found outside the scope that this test is
|
Chris@17
|
177 * listening to.
|
Chris@17
|
178 *
|
Chris@17
|
179 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
|
Chris@17
|
180 * @param int $stackPtr The position in the stack where this
|
Chris@17
|
181 * token was found.
|
Chris@17
|
182 *
|
Chris@17
|
183 * @return void|int Optionally returns a stack pointer. The sniff will not be
|
Chris@17
|
184 * called again on the current file until the returned stack
|
Chris@17
|
185 * pointer is reached. Return (count($tokens) + 1) to skip
|
Chris@17
|
186 * the rest of the file.
|
Chris@17
|
187 */
|
Chris@17
|
188 abstract protected function processTokenOutsideScope(File $phpcsFile, $stackPtr);
|
Chris@17
|
189
|
Chris@17
|
190
|
Chris@17
|
191 }//end class
|