3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Code\Scanner
;
12 use Zend\Code\Annotation\AnnotationManager
;
13 use Zend\Code\Exception
;
14 use Zend\Code\NameInformation
;
16 class MethodScanner
implements ScannerInterface
21 protected $isScanned = false;
26 protected $docComment = null;
31 protected $scannerClass = null;
36 protected $class = null;
41 protected $name = null;
46 protected $lineStart = null;
51 protected $lineEnd = null;
56 protected $isFinal = false;
61 protected $isAbstract = false;
66 protected $isPublic = true;
71 protected $isProtected = false;
76 protected $isPrivate = false;
81 protected $isStatic = false;
91 protected $tokens = array();
94 * @var NameInformation
96 protected $nameInformation = null;
101 protected $infos = array();
104 * @param array $methodTokens
105 * @param NameInformation $nameInformation
107 public function __construct(array $methodTokens, NameInformation
$nameInformation = null)
109 $this->tokens
= $methodTokens;
110 $this->nameInformation
= $nameInformation;
114 * @param string $class
115 * @return MethodScanner
117 public function setClass($class)
119 $this->class = (string) $class;
124 * @param ClassScanner $scannerClass
125 * @return MethodScanner
127 public function setScannerClass(ClassScanner
$scannerClass)
129 $this->scannerClass
= $scannerClass;
134 * @return MethodScanner
136 public function getClassScanner()
138 return $this->scannerClass
;
144 public function getName()
154 public function getLineStart()
158 return $this->lineStart
;
164 public function getLineEnd()
168 return $this->lineEnd
;
174 public function getDocComment()
178 return $this->docComment
;
182 * @param AnnotationManager $annotationManager
183 * @return AnnotationScanner
185 public function getAnnotations(AnnotationManager
$annotationManager)
187 if (($docComment = $this->getDocComment()) == '') {
191 return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation
);
197 public function isFinal()
201 return $this->isFinal
;
207 public function isAbstract()
211 return $this->isAbstract
;
217 public function isPublic()
221 return $this->isPublic
;
227 public function isProtected()
231 return $this->isProtected
;
237 public function isPrivate()
241 return $this->isPrivate
;
247 public function isStatic()
251 return $this->isStatic
;
257 public function getNumberOfParameters()
259 return count($this->getParameters());
263 * @param bool $returnScanner
266 public function getParameters($returnScanner = false)
272 foreach ($this->infos
as $info) {
273 if ($info['type'] != 'parameter') {
277 if (!$returnScanner) {
278 $return[] = $info['name'];
280 $return[] = $this->getParameter($info['name']);
288 * @param int|string $parameterNameOrInfoIndex
289 * @return ParameterScanner
290 * @throws Exception\InvalidArgumentException
292 public function getParameter($parameterNameOrInfoIndex)
296 if (is_int($parameterNameOrInfoIndex)) {
297 $info = $this->infos
[$parameterNameOrInfoIndex];
298 if ($info['type'] != 'parameter') {
299 throw new Exception\
InvalidArgumentException('Index of info offset is not about a parameter');
301 } elseif (is_string($parameterNameOrInfoIndex)) {
302 foreach ($this->infos
as $info) {
303 if ($info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) {
309 throw new Exception\
InvalidArgumentException('Index of info offset is not about a parameter');
313 $p = new ParameterScanner(
314 array_slice($this->tokens
, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart']),
315 $this->nameInformation
317 $p->setDeclaringFunction($this->name
);
318 $p->setDeclaringScannerFunction($this);
319 $p->setDeclaringClass($this->class);
320 $p->setDeclaringScannerClass($this->scannerClass
);
321 $p->setPosition($info['position']);
329 public function getBody()
336 public static function export()
341 public function __toString()
345 return var_export($this, true);
348 protected function scan()
350 if ($this->isScanned
) {
354 if (!$this->tokens
) {
355 throw new Exception\
RuntimeException('No tokens were provided');
362 $tokens = &$this->tokens
; // localize
363 $infos = &$this->infos
; // localize
367 $tokenContent = null;
375 $MACRO_TOKEN_ADVANCE = function () use (&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) {
376 static $lastTokenArray = null;
377 $tokenIndex = ($tokenIndex === null) ?
0 : $tokenIndex +
1;
378 if (!isset($tokens[$tokenIndex])) {
380 $tokenContent = false;
386 $token = $tokens[$tokenIndex];
387 if (is_string($token)) {
389 $tokenContent = $token;
390 $tokenLine = $tokenLine +
substr_count($lastTokenArray[1],
391 "\n"); // adjust token line by last known newline count
393 list($tokenType, $tokenContent, $tokenLine) = $token;
398 $MACRO_INFO_START = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
399 $infos[$infoIndex] = array(
400 'type' => 'parameter',
401 'tokenStart' => $tokenIndex,
403 'lineStart' => $tokenLine,
404 'lineEnd' => $tokenLine,
406 'position' => $infoIndex +
1, // position is +1 of infoIndex
409 $MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
410 $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
411 $infos[$infoIndex]['lineEnd'] = $tokenLine;
418 * START FINITE STATE MACHINE FOR SCANNING TOKENS
422 $MACRO_TOKEN_ADVANCE();
426 $this->lineStart
= ($this->lineStart
) ?
: $tokenLine;
428 switch ($tokenType) {
430 $this->lineStart
= null;
431 if ($this->docComment
=== null && $this->name
=== null) {
432 $this->docComment
= $tokenContent;
434 goto SCANNER_CONTINUE_SIGNATURE
;
437 $this->isFinal
= true;
438 goto SCANNER_CONTINUE_SIGNATURE
;
441 $this->isAbstract
= true;
442 goto SCANNER_CONTINUE_SIGNATURE
;
446 goto SCANNER_CONTINUE_SIGNATURE
;
449 $this->isProtected
= true;
450 $this->isPublic
= false;
451 goto SCANNER_CONTINUE_SIGNATURE
;
454 $this->isPrivate
= true;
455 $this->isPublic
= false;
456 goto SCANNER_CONTINUE_SIGNATURE
;
459 $this->isStatic
= true;
460 goto SCANNER_CONTINUE_SIGNATURE
;
465 if ($tokenType === T_STRING
&& $parentCount === 0) {
466 $this->name
= $tokenContent;
469 if ($parentCount === 1) {
470 if (!isset($infos[$infoIndex])) {
473 if ($tokenType === T_VARIABLE
) {
474 $infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
478 goto SCANNER_CONTINUE_SIGNATURE
;
482 switch ($tokenContent) {
484 if (!isset($infos[$infoIndex])) {
487 goto SCANNER_CONTINUE_SIGNATURE
;
490 goto SCANNER_CONTINUE_SIGNATURE
;
493 if ($parentCount === 0) {
495 $MACRO_INFO_ADVANCE();
499 goto SCANNER_CONTINUE_BODY
;
501 if ($parentCount === 1) {
502 $MACRO_INFO_ADVANCE();
504 goto SCANNER_CONTINUE_SIGNATURE
;
508 SCANNER_CONTINUE_SIGNATURE
:
510 if ($MACRO_TOKEN_ADVANCE() === false) {
515 SCANNER_CONTINUE_BODY
:
518 while ($MACRO_TOKEN_ADVANCE() !== false) {
519 if ($tokenContent == '}') {
522 if ($braceCount > 0) {
523 $this->body
.= $tokenContent;
525 if ($tokenContent == '{') {
528 $this->lineEnd
= $tokenLine;
533 $this->isScanned
= true;