Chris@0
|
1 <?php
|
Chris@0
|
2 /*
|
Chris@0
|
3 * This file is part of the PHP_TokenStream package.
|
Chris@0
|
4 *
|
Chris@0
|
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@0
|
6 *
|
Chris@0
|
7 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
8 * file that was distributed with this source code.
|
Chris@0
|
9 */
|
Chris@0
|
10
|
Chris@0
|
11 /**
|
Chris@0
|
12 * A stream of PHP tokens.
|
Chris@0
|
13 *
|
Chris@0
|
14 * @author Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@0
|
15 * @copyright Sebastian Bergmann <sebastian@phpunit.de>
|
Chris@0
|
16 * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
|
Chris@0
|
17 * @link http://github.com/sebastianbergmann/php-token-stream/tree
|
Chris@0
|
18 * @since Class available since Release 1.0.0
|
Chris@0
|
19 */
|
Chris@0
|
20 class PHP_Token_Stream implements ArrayAccess, Countable, SeekableIterator
|
Chris@0
|
21 {
|
Chris@0
|
22 /**
|
Chris@0
|
23 * @var array
|
Chris@0
|
24 */
|
Chris@0
|
25 protected static $customTokens = array(
|
Chris@0
|
26 '(' => 'PHP_Token_OPEN_BRACKET',
|
Chris@0
|
27 ')' => 'PHP_Token_CLOSE_BRACKET',
|
Chris@0
|
28 '[' => 'PHP_Token_OPEN_SQUARE',
|
Chris@0
|
29 ']' => 'PHP_Token_CLOSE_SQUARE',
|
Chris@0
|
30 '{' => 'PHP_Token_OPEN_CURLY',
|
Chris@0
|
31 '}' => 'PHP_Token_CLOSE_CURLY',
|
Chris@0
|
32 ';' => 'PHP_Token_SEMICOLON',
|
Chris@0
|
33 '.' => 'PHP_Token_DOT',
|
Chris@0
|
34 ',' => 'PHP_Token_COMMA',
|
Chris@0
|
35 '=' => 'PHP_Token_EQUAL',
|
Chris@0
|
36 '<' => 'PHP_Token_LT',
|
Chris@0
|
37 '>' => 'PHP_Token_GT',
|
Chris@0
|
38 '+' => 'PHP_Token_PLUS',
|
Chris@0
|
39 '-' => 'PHP_Token_MINUS',
|
Chris@0
|
40 '*' => 'PHP_Token_MULT',
|
Chris@0
|
41 '/' => 'PHP_Token_DIV',
|
Chris@0
|
42 '?' => 'PHP_Token_QUESTION_MARK',
|
Chris@0
|
43 '!' => 'PHP_Token_EXCLAMATION_MARK',
|
Chris@0
|
44 ':' => 'PHP_Token_COLON',
|
Chris@0
|
45 '"' => 'PHP_Token_DOUBLE_QUOTES',
|
Chris@0
|
46 '@' => 'PHP_Token_AT',
|
Chris@0
|
47 '&' => 'PHP_Token_AMPERSAND',
|
Chris@0
|
48 '%' => 'PHP_Token_PERCENT',
|
Chris@0
|
49 '|' => 'PHP_Token_PIPE',
|
Chris@0
|
50 '$' => 'PHP_Token_DOLLAR',
|
Chris@0
|
51 '^' => 'PHP_Token_CARET',
|
Chris@0
|
52 '~' => 'PHP_Token_TILDE',
|
Chris@0
|
53 '`' => 'PHP_Token_BACKTICK'
|
Chris@0
|
54 );
|
Chris@0
|
55
|
Chris@0
|
56 /**
|
Chris@0
|
57 * @var string
|
Chris@0
|
58 */
|
Chris@0
|
59 protected $filename;
|
Chris@0
|
60
|
Chris@0
|
61 /**
|
Chris@0
|
62 * @var array
|
Chris@0
|
63 */
|
Chris@0
|
64 protected $tokens = array();
|
Chris@0
|
65
|
Chris@0
|
66 /**
|
Chris@0
|
67 * @var integer
|
Chris@0
|
68 */
|
Chris@0
|
69 protected $position = 0;
|
Chris@0
|
70
|
Chris@0
|
71 /**
|
Chris@0
|
72 * @var array
|
Chris@0
|
73 */
|
Chris@0
|
74 protected $linesOfCode = array('loc' => 0, 'cloc' => 0, 'ncloc' => 0);
|
Chris@0
|
75
|
Chris@0
|
76 /**
|
Chris@0
|
77 * @var array
|
Chris@0
|
78 */
|
Chris@0
|
79 protected $classes;
|
Chris@0
|
80
|
Chris@0
|
81 /**
|
Chris@0
|
82 * @var array
|
Chris@0
|
83 */
|
Chris@0
|
84 protected $functions;
|
Chris@0
|
85
|
Chris@0
|
86 /**
|
Chris@0
|
87 * @var array
|
Chris@0
|
88 */
|
Chris@0
|
89 protected $includes;
|
Chris@0
|
90
|
Chris@0
|
91 /**
|
Chris@0
|
92 * @var array
|
Chris@0
|
93 */
|
Chris@0
|
94 protected $interfaces;
|
Chris@0
|
95
|
Chris@0
|
96 /**
|
Chris@0
|
97 * @var array
|
Chris@0
|
98 */
|
Chris@0
|
99 protected $traits;
|
Chris@0
|
100
|
Chris@0
|
101 /**
|
Chris@0
|
102 * @var array
|
Chris@0
|
103 */
|
Chris@0
|
104 protected $lineToFunctionMap = array();
|
Chris@0
|
105
|
Chris@0
|
106 /**
|
Chris@0
|
107 * Constructor.
|
Chris@0
|
108 *
|
Chris@0
|
109 * @param string $sourceCode
|
Chris@0
|
110 */
|
Chris@0
|
111 public function __construct($sourceCode)
|
Chris@0
|
112 {
|
Chris@0
|
113 if (is_file($sourceCode)) {
|
Chris@0
|
114 $this->filename = $sourceCode;
|
Chris@0
|
115 $sourceCode = file_get_contents($sourceCode);
|
Chris@0
|
116 }
|
Chris@0
|
117
|
Chris@0
|
118 $this->scan($sourceCode);
|
Chris@0
|
119 }
|
Chris@0
|
120
|
Chris@0
|
121 /**
|
Chris@0
|
122 * Destructor.
|
Chris@0
|
123 */
|
Chris@0
|
124 public function __destruct()
|
Chris@0
|
125 {
|
Chris@0
|
126 $this->tokens = array();
|
Chris@0
|
127 }
|
Chris@0
|
128
|
Chris@0
|
129 /**
|
Chris@0
|
130 * @return string
|
Chris@0
|
131 */
|
Chris@0
|
132 public function __toString()
|
Chris@0
|
133 {
|
Chris@0
|
134 $buffer = '';
|
Chris@0
|
135
|
Chris@0
|
136 foreach ($this as $token) {
|
Chris@0
|
137 $buffer .= $token;
|
Chris@0
|
138 }
|
Chris@0
|
139
|
Chris@0
|
140 return $buffer;
|
Chris@0
|
141 }
|
Chris@0
|
142
|
Chris@0
|
143 /**
|
Chris@0
|
144 * @return string
|
Chris@0
|
145 * @since Method available since Release 1.1.0
|
Chris@0
|
146 */
|
Chris@0
|
147 public function getFilename()
|
Chris@0
|
148 {
|
Chris@0
|
149 return $this->filename;
|
Chris@0
|
150 }
|
Chris@0
|
151
|
Chris@0
|
152 /**
|
Chris@0
|
153 * Scans the source for sequences of characters and converts them into a
|
Chris@0
|
154 * stream of tokens.
|
Chris@0
|
155 *
|
Chris@0
|
156 * @param string $sourceCode
|
Chris@0
|
157 */
|
Chris@0
|
158 protected function scan($sourceCode)
|
Chris@0
|
159 {
|
Chris@0
|
160 $id = 0;
|
Chris@0
|
161 $line = 1;
|
Chris@0
|
162 $tokens = token_get_all($sourceCode);
|
Chris@0
|
163 $numTokens = count($tokens);
|
Chris@0
|
164
|
Chris@0
|
165 $lastNonWhitespaceTokenWasDoubleColon = false;
|
Chris@0
|
166
|
Chris@0
|
167 for ($i = 0; $i < $numTokens; ++$i) {
|
Chris@0
|
168 $token = $tokens[$i];
|
Chris@0
|
169 $skip = 0;
|
Chris@0
|
170
|
Chris@0
|
171 if (is_array($token)) {
|
Chris@0
|
172 $name = substr(token_name($token[0]), 2);
|
Chris@0
|
173 $text = $token[1];
|
Chris@0
|
174
|
Chris@0
|
175 if ($lastNonWhitespaceTokenWasDoubleColon && $name == 'CLASS') {
|
Chris@0
|
176 $name = 'CLASS_NAME_CONSTANT';
|
Chris@0
|
177 } elseif ($name == 'USE' && isset($tokens[$i+2][0]) && $tokens[$i+2][0] == T_FUNCTION) {
|
Chris@0
|
178 $name = 'USE_FUNCTION';
|
Chris@12
|
179 $text .= $tokens[$i+1][1] . $tokens[$i+2][1];
|
Chris@0
|
180 $skip = 2;
|
Chris@0
|
181 }
|
Chris@0
|
182
|
Chris@0
|
183 $tokenClass = 'PHP_Token_' . $name;
|
Chris@0
|
184 } else {
|
Chris@0
|
185 $text = $token;
|
Chris@0
|
186 $tokenClass = self::$customTokens[$token];
|
Chris@0
|
187 }
|
Chris@0
|
188
|
Chris@0
|
189 $this->tokens[] = new $tokenClass($text, $line, $this, $id++);
|
Chris@0
|
190 $lines = substr_count($text, "\n");
|
Chris@0
|
191 $line += $lines;
|
Chris@0
|
192
|
Chris@0
|
193 if ($tokenClass == 'PHP_Token_HALT_COMPILER') {
|
Chris@0
|
194 break;
|
Chris@0
|
195 } elseif ($tokenClass == 'PHP_Token_COMMENT' ||
|
Chris@0
|
196 $tokenClass == 'PHP_Token_DOC_COMMENT') {
|
Chris@0
|
197 $this->linesOfCode['cloc'] += $lines + 1;
|
Chris@0
|
198 }
|
Chris@0
|
199
|
Chris@0
|
200 if ($name == 'DOUBLE_COLON') {
|
Chris@0
|
201 $lastNonWhitespaceTokenWasDoubleColon = true;
|
Chris@0
|
202 } elseif ($name != 'WHITESPACE') {
|
Chris@0
|
203 $lastNonWhitespaceTokenWasDoubleColon = false;
|
Chris@0
|
204 }
|
Chris@0
|
205
|
Chris@0
|
206 $i += $skip;
|
Chris@0
|
207 }
|
Chris@0
|
208
|
Chris@0
|
209 $this->linesOfCode['loc'] = substr_count($sourceCode, "\n");
|
Chris@0
|
210 $this->linesOfCode['ncloc'] = $this->linesOfCode['loc'] -
|
Chris@0
|
211 $this->linesOfCode['cloc'];
|
Chris@0
|
212 }
|
Chris@0
|
213
|
Chris@0
|
214 /**
|
Chris@0
|
215 * @return integer
|
Chris@0
|
216 */
|
Chris@0
|
217 public function count()
|
Chris@0
|
218 {
|
Chris@0
|
219 return count($this->tokens);
|
Chris@0
|
220 }
|
Chris@0
|
221
|
Chris@0
|
222 /**
|
Chris@0
|
223 * @return PHP_Token[]
|
Chris@0
|
224 */
|
Chris@0
|
225 public function tokens()
|
Chris@0
|
226 {
|
Chris@0
|
227 return $this->tokens;
|
Chris@0
|
228 }
|
Chris@0
|
229
|
Chris@0
|
230 /**
|
Chris@0
|
231 * @return array
|
Chris@0
|
232 */
|
Chris@0
|
233 public function getClasses()
|
Chris@0
|
234 {
|
Chris@0
|
235 if ($this->classes !== null) {
|
Chris@0
|
236 return $this->classes;
|
Chris@0
|
237 }
|
Chris@0
|
238
|
Chris@0
|
239 $this->parse();
|
Chris@0
|
240
|
Chris@0
|
241 return $this->classes;
|
Chris@0
|
242 }
|
Chris@0
|
243
|
Chris@0
|
244 /**
|
Chris@0
|
245 * @return array
|
Chris@0
|
246 */
|
Chris@0
|
247 public function getFunctions()
|
Chris@0
|
248 {
|
Chris@0
|
249 if ($this->functions !== null) {
|
Chris@0
|
250 return $this->functions;
|
Chris@0
|
251 }
|
Chris@0
|
252
|
Chris@0
|
253 $this->parse();
|
Chris@0
|
254
|
Chris@0
|
255 return $this->functions;
|
Chris@0
|
256 }
|
Chris@0
|
257
|
Chris@0
|
258 /**
|
Chris@0
|
259 * @return array
|
Chris@0
|
260 */
|
Chris@0
|
261 public function getInterfaces()
|
Chris@0
|
262 {
|
Chris@0
|
263 if ($this->interfaces !== null) {
|
Chris@0
|
264 return $this->interfaces;
|
Chris@0
|
265 }
|
Chris@0
|
266
|
Chris@0
|
267 $this->parse();
|
Chris@0
|
268
|
Chris@0
|
269 return $this->interfaces;
|
Chris@0
|
270 }
|
Chris@0
|
271
|
Chris@0
|
272 /**
|
Chris@0
|
273 * @return array
|
Chris@0
|
274 * @since Method available since Release 1.1.0
|
Chris@0
|
275 */
|
Chris@0
|
276 public function getTraits()
|
Chris@0
|
277 {
|
Chris@0
|
278 if ($this->traits !== null) {
|
Chris@0
|
279 return $this->traits;
|
Chris@0
|
280 }
|
Chris@0
|
281
|
Chris@0
|
282 $this->parse();
|
Chris@0
|
283
|
Chris@0
|
284 return $this->traits;
|
Chris@0
|
285 }
|
Chris@0
|
286
|
Chris@0
|
287 /**
|
Chris@0
|
288 * Gets the names of all files that have been included
|
Chris@0
|
289 * using include(), include_once(), require() or require_once().
|
Chris@0
|
290 *
|
Chris@0
|
291 * Parameter $categorize set to TRUE causing this function to return a
|
Chris@0
|
292 * multi-dimensional array with categories in the keys of the first dimension
|
Chris@0
|
293 * and constants and their values in the second dimension.
|
Chris@0
|
294 *
|
Chris@0
|
295 * Parameter $category allow to filter following specific inclusion type
|
Chris@0
|
296 *
|
Chris@0
|
297 * @param bool $categorize OPTIONAL
|
Chris@0
|
298 * @param string $category OPTIONAL Either 'require_once', 'require',
|
Chris@0
|
299 * 'include_once', 'include'.
|
Chris@0
|
300 * @return array
|
Chris@0
|
301 * @since Method available since Release 1.1.0
|
Chris@0
|
302 */
|
Chris@0
|
303 public function getIncludes($categorize = false, $category = null)
|
Chris@0
|
304 {
|
Chris@0
|
305 if ($this->includes === null) {
|
Chris@0
|
306 $this->includes = array(
|
Chris@0
|
307 'require_once' => array(),
|
Chris@0
|
308 'require' => array(),
|
Chris@0
|
309 'include_once' => array(),
|
Chris@0
|
310 'include' => array()
|
Chris@0
|
311 );
|
Chris@0
|
312
|
Chris@0
|
313 foreach ($this->tokens as $token) {
|
Chris@0
|
314 switch (get_class($token)) {
|
Chris@0
|
315 case 'PHP_Token_REQUIRE_ONCE':
|
Chris@0
|
316 case 'PHP_Token_REQUIRE':
|
Chris@0
|
317 case 'PHP_Token_INCLUDE_ONCE':
|
Chris@0
|
318 case 'PHP_Token_INCLUDE':
|
Chris@0
|
319 $this->includes[$token->getType()][] = $token->getName();
|
Chris@0
|
320 break;
|
Chris@0
|
321 }
|
Chris@0
|
322 }
|
Chris@0
|
323 }
|
Chris@0
|
324
|
Chris@0
|
325 if (isset($this->includes[$category])) {
|
Chris@0
|
326 $includes = $this->includes[$category];
|
Chris@0
|
327 } elseif ($categorize === false) {
|
Chris@0
|
328 $includes = array_merge(
|
Chris@0
|
329 $this->includes['require_once'],
|
Chris@0
|
330 $this->includes['require'],
|
Chris@0
|
331 $this->includes['include_once'],
|
Chris@0
|
332 $this->includes['include']
|
Chris@0
|
333 );
|
Chris@0
|
334 } else {
|
Chris@0
|
335 $includes = $this->includes;
|
Chris@0
|
336 }
|
Chris@0
|
337
|
Chris@0
|
338 return $includes;
|
Chris@0
|
339 }
|
Chris@0
|
340
|
Chris@0
|
341 /**
|
Chris@0
|
342 * Returns the name of the function or method a line belongs to.
|
Chris@0
|
343 *
|
Chris@0
|
344 * @return string or null if the line is not in a function or method
|
Chris@0
|
345 * @since Method available since Release 1.2.0
|
Chris@0
|
346 */
|
Chris@0
|
347 public function getFunctionForLine($line)
|
Chris@0
|
348 {
|
Chris@0
|
349 $this->parse();
|
Chris@0
|
350
|
Chris@0
|
351 if (isset($this->lineToFunctionMap[$line])) {
|
Chris@0
|
352 return $this->lineToFunctionMap[$line];
|
Chris@0
|
353 }
|
Chris@0
|
354 }
|
Chris@0
|
355
|
Chris@0
|
356 protected function parse()
|
Chris@0
|
357 {
|
Chris@0
|
358 $this->interfaces = array();
|
Chris@0
|
359 $this->classes = array();
|
Chris@0
|
360 $this->traits = array();
|
Chris@0
|
361 $this->functions = array();
|
Chris@0
|
362 $class = array();
|
Chris@0
|
363 $classEndLine = array();
|
Chris@0
|
364 $trait = false;
|
Chris@0
|
365 $traitEndLine = false;
|
Chris@0
|
366 $interface = false;
|
Chris@0
|
367 $interfaceEndLine = false;
|
Chris@0
|
368
|
Chris@0
|
369 foreach ($this->tokens as $token) {
|
Chris@0
|
370 switch (get_class($token)) {
|
Chris@0
|
371 case 'PHP_Token_HALT_COMPILER':
|
Chris@0
|
372 return;
|
Chris@0
|
373
|
Chris@0
|
374 case 'PHP_Token_INTERFACE':
|
Chris@0
|
375 $interface = $token->getName();
|
Chris@0
|
376 $interfaceEndLine = $token->getEndLine();
|
Chris@0
|
377
|
Chris@0
|
378 $this->interfaces[$interface] = array(
|
Chris@0
|
379 'methods' => array(),
|
Chris@0
|
380 'parent' => $token->getParent(),
|
Chris@0
|
381 'keywords' => $token->getKeywords(),
|
Chris@0
|
382 'docblock' => $token->getDocblock(),
|
Chris@0
|
383 'startLine' => $token->getLine(),
|
Chris@0
|
384 'endLine' => $interfaceEndLine,
|
Chris@0
|
385 'package' => $token->getPackage(),
|
Chris@0
|
386 'file' => $this->filename
|
Chris@0
|
387 );
|
Chris@0
|
388 break;
|
Chris@0
|
389
|
Chris@0
|
390 case 'PHP_Token_CLASS':
|
Chris@0
|
391 case 'PHP_Token_TRAIT':
|
Chris@0
|
392 $tmp = array(
|
Chris@0
|
393 'methods' => array(),
|
Chris@0
|
394 'parent' => $token->getParent(),
|
Chris@0
|
395 'interfaces'=> $token->getInterfaces(),
|
Chris@0
|
396 'keywords' => $token->getKeywords(),
|
Chris@0
|
397 'docblock' => $token->getDocblock(),
|
Chris@0
|
398 'startLine' => $token->getLine(),
|
Chris@0
|
399 'endLine' => $token->getEndLine(),
|
Chris@0
|
400 'package' => $token->getPackage(),
|
Chris@0
|
401 'file' => $this->filename
|
Chris@0
|
402 );
|
Chris@0
|
403
|
Chris@0
|
404 if ($token instanceof PHP_Token_CLASS) {
|
Chris@0
|
405 $class[] = $token->getName();
|
Chris@0
|
406 $classEndLine[] = $token->getEndLine();
|
Chris@0
|
407
|
Chris@0
|
408 if ($class[count($class)-1] != 'anonymous class') {
|
Chris@0
|
409 $this->classes[$class[count($class)-1]] = $tmp;
|
Chris@0
|
410 }
|
Chris@0
|
411 } else {
|
Chris@0
|
412 $trait = $token->getName();
|
Chris@0
|
413 $traitEndLine = $token->getEndLine();
|
Chris@0
|
414 $this->traits[$trait] = $tmp;
|
Chris@0
|
415 }
|
Chris@0
|
416 break;
|
Chris@0
|
417
|
Chris@0
|
418 case 'PHP_Token_FUNCTION':
|
Chris@0
|
419 $name = $token->getName();
|
Chris@0
|
420 $tmp = array(
|
Chris@0
|
421 'docblock' => $token->getDocblock(),
|
Chris@0
|
422 'keywords' => $token->getKeywords(),
|
Chris@0
|
423 'visibility'=> $token->getVisibility(),
|
Chris@0
|
424 'signature' => $token->getSignature(),
|
Chris@0
|
425 'startLine' => $token->getLine(),
|
Chris@0
|
426 'endLine' => $token->getEndLine(),
|
Chris@0
|
427 'ccn' => $token->getCCN(),
|
Chris@0
|
428 'file' => $this->filename
|
Chris@0
|
429 );
|
Chris@0
|
430
|
Chris@0
|
431 if (empty($class) &&
|
Chris@0
|
432 $trait === false &&
|
Chris@0
|
433 $interface === false) {
|
Chris@0
|
434 $this->functions[$name] = $tmp;
|
Chris@0
|
435
|
Chris@0
|
436 $this->addFunctionToMap(
|
Chris@0
|
437 $name,
|
Chris@0
|
438 $tmp['startLine'],
|
Chris@0
|
439 $tmp['endLine']
|
Chris@0
|
440 );
|
Chris@0
|
441 } elseif (!empty($class) && $class[count($class)-1] != 'anonymous class') {
|
Chris@0
|
442 $this->classes[$class[count($class)-1]]['methods'][$name] = $tmp;
|
Chris@0
|
443
|
Chris@0
|
444 $this->addFunctionToMap(
|
Chris@0
|
445 $class[count($class)-1] . '::' . $name,
|
Chris@0
|
446 $tmp['startLine'],
|
Chris@0
|
447 $tmp['endLine']
|
Chris@0
|
448 );
|
Chris@0
|
449 } elseif ($trait !== false) {
|
Chris@0
|
450 $this->traits[$trait]['methods'][$name] = $tmp;
|
Chris@0
|
451
|
Chris@0
|
452 $this->addFunctionToMap(
|
Chris@0
|
453 $trait . '::' . $name,
|
Chris@0
|
454 $tmp['startLine'],
|
Chris@0
|
455 $tmp['endLine']
|
Chris@0
|
456 );
|
Chris@0
|
457 } else {
|
Chris@0
|
458 $this->interfaces[$interface]['methods'][$name] = $tmp;
|
Chris@0
|
459 }
|
Chris@0
|
460 break;
|
Chris@0
|
461
|
Chris@0
|
462 case 'PHP_Token_CLOSE_CURLY':
|
Chris@0
|
463 if (!empty($classEndLine) &&
|
Chris@0
|
464 $classEndLine[count($classEndLine)-1] == $token->getLine()) {
|
Chris@0
|
465 array_pop($classEndLine);
|
Chris@0
|
466 array_pop($class);
|
Chris@0
|
467 } elseif ($traitEndLine !== false &&
|
Chris@0
|
468 $traitEndLine == $token->getLine()) {
|
Chris@0
|
469 $trait = false;
|
Chris@0
|
470 $traitEndLine = false;
|
Chris@0
|
471 } elseif ($interfaceEndLine !== false &&
|
Chris@0
|
472 $interfaceEndLine == $token->getLine()) {
|
Chris@0
|
473 $interface = false;
|
Chris@0
|
474 $interfaceEndLine = false;
|
Chris@0
|
475 }
|
Chris@0
|
476 break;
|
Chris@0
|
477 }
|
Chris@0
|
478 }
|
Chris@0
|
479 }
|
Chris@0
|
480
|
Chris@0
|
481 /**
|
Chris@0
|
482 * @return array
|
Chris@0
|
483 */
|
Chris@0
|
484 public function getLinesOfCode()
|
Chris@0
|
485 {
|
Chris@0
|
486 return $this->linesOfCode;
|
Chris@0
|
487 }
|
Chris@0
|
488
|
Chris@0
|
489 /**
|
Chris@0
|
490 */
|
Chris@0
|
491 public function rewind()
|
Chris@0
|
492 {
|
Chris@0
|
493 $this->position = 0;
|
Chris@0
|
494 }
|
Chris@0
|
495
|
Chris@0
|
496 /**
|
Chris@0
|
497 * @return boolean
|
Chris@0
|
498 */
|
Chris@0
|
499 public function valid()
|
Chris@0
|
500 {
|
Chris@0
|
501 return isset($this->tokens[$this->position]);
|
Chris@0
|
502 }
|
Chris@0
|
503
|
Chris@0
|
504 /**
|
Chris@0
|
505 * @return integer
|
Chris@0
|
506 */
|
Chris@0
|
507 public function key()
|
Chris@0
|
508 {
|
Chris@0
|
509 return $this->position;
|
Chris@0
|
510 }
|
Chris@0
|
511
|
Chris@0
|
512 /**
|
Chris@0
|
513 * @return PHP_Token
|
Chris@0
|
514 */
|
Chris@0
|
515 public function current()
|
Chris@0
|
516 {
|
Chris@0
|
517 return $this->tokens[$this->position];
|
Chris@0
|
518 }
|
Chris@0
|
519
|
Chris@0
|
520 /**
|
Chris@0
|
521 */
|
Chris@0
|
522 public function next()
|
Chris@0
|
523 {
|
Chris@0
|
524 $this->position++;
|
Chris@0
|
525 }
|
Chris@0
|
526
|
Chris@0
|
527 /**
|
Chris@0
|
528 * @param integer $offset
|
Chris@0
|
529 * @return boolean
|
Chris@0
|
530 */
|
Chris@0
|
531 public function offsetExists($offset)
|
Chris@0
|
532 {
|
Chris@0
|
533 return isset($this->tokens[$offset]);
|
Chris@0
|
534 }
|
Chris@0
|
535
|
Chris@0
|
536 /**
|
Chris@0
|
537 * @param integer $offset
|
Chris@0
|
538 * @return mixed
|
Chris@0
|
539 * @throws OutOfBoundsException
|
Chris@0
|
540 */
|
Chris@0
|
541 public function offsetGet($offset)
|
Chris@0
|
542 {
|
Chris@0
|
543 if (!$this->offsetExists($offset)) {
|
Chris@0
|
544 throw new OutOfBoundsException(
|
Chris@0
|
545 sprintf(
|
Chris@0
|
546 'No token at position "%s"',
|
Chris@0
|
547 $offset
|
Chris@0
|
548 )
|
Chris@0
|
549 );
|
Chris@0
|
550 }
|
Chris@0
|
551
|
Chris@0
|
552 return $this->tokens[$offset];
|
Chris@0
|
553 }
|
Chris@0
|
554
|
Chris@0
|
555 /**
|
Chris@0
|
556 * @param integer $offset
|
Chris@0
|
557 * @param mixed $value
|
Chris@0
|
558 */
|
Chris@0
|
559 public function offsetSet($offset, $value)
|
Chris@0
|
560 {
|
Chris@0
|
561 $this->tokens[$offset] = $value;
|
Chris@0
|
562 }
|
Chris@0
|
563
|
Chris@0
|
564 /**
|
Chris@0
|
565 * @param integer $offset
|
Chris@0
|
566 * @throws OutOfBoundsException
|
Chris@0
|
567 */
|
Chris@0
|
568 public function offsetUnset($offset)
|
Chris@0
|
569 {
|
Chris@0
|
570 if (!$this->offsetExists($offset)) {
|
Chris@0
|
571 throw new OutOfBoundsException(
|
Chris@0
|
572 sprintf(
|
Chris@0
|
573 'No token at position "%s"',
|
Chris@0
|
574 $offset
|
Chris@0
|
575 )
|
Chris@0
|
576 );
|
Chris@0
|
577 }
|
Chris@0
|
578
|
Chris@0
|
579 unset($this->tokens[$offset]);
|
Chris@0
|
580 }
|
Chris@0
|
581
|
Chris@0
|
582 /**
|
Chris@0
|
583 * Seek to an absolute position.
|
Chris@0
|
584 *
|
Chris@0
|
585 * @param integer $position
|
Chris@0
|
586 * @throws OutOfBoundsException
|
Chris@0
|
587 */
|
Chris@0
|
588 public function seek($position)
|
Chris@0
|
589 {
|
Chris@0
|
590 $this->position = $position;
|
Chris@0
|
591
|
Chris@0
|
592 if (!$this->valid()) {
|
Chris@0
|
593 throw new OutOfBoundsException(
|
Chris@0
|
594 sprintf(
|
Chris@0
|
595 'No token at position "%s"',
|
Chris@0
|
596 $this->position
|
Chris@0
|
597 )
|
Chris@0
|
598 );
|
Chris@0
|
599 }
|
Chris@0
|
600 }
|
Chris@0
|
601
|
Chris@0
|
602 /**
|
Chris@0
|
603 * @param string $name
|
Chris@0
|
604 * @param integer $startLine
|
Chris@0
|
605 * @param integer $endLine
|
Chris@0
|
606 */
|
Chris@0
|
607 private function addFunctionToMap($name, $startLine, $endLine)
|
Chris@0
|
608 {
|
Chris@0
|
609 for ($line = $startLine; $line <= $endLine; $line++) {
|
Chris@0
|
610 $this->lineToFunctionMap[$line] = $name;
|
Chris@0
|
611 }
|
Chris@0
|
612 }
|
Chris@0
|
613 }
|