3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 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
;
255 * Override the given name for a method, this is necessary to
261 public function setName($name)
268 * Visibility must be of T_PUBLIC, T_PRIVATE or T_PROTECTED
269 * Needed to support traits
271 * @param $visibility T_PUBLIC | T_PRIVATE | T_PROTECTED
273 * @throws \Zend\Code\Exception
275 public function setVisibility($visibility)
277 switch (strtolower($visibility)) {
279 $this->isPublic
= true;
280 $this->isPrivate
= false;
281 $this->isProtected
= false;
285 $this->isPublic
= false;
286 $this->isPrivate
= true;
287 $this->isProtected
= false;
291 $this->isPublic
= false;
292 $this->isPrivate
= false;
293 $this->isProtected
= true;
297 throw new Exception("Invalid visibility argument passed to setVisibility.");
306 public function getNumberOfParameters()
308 return count($this->getParameters());
312 * @param bool $returnScanner
315 public function getParameters($returnScanner = false)
321 foreach ($this->infos
as $info) {
322 if ($info['type'] != 'parameter') {
326 if (!$returnScanner) {
327 $return[] = $info['name'];
329 $return[] = $this->getParameter($info['name']);
337 * @param int|string $parameterNameOrInfoIndex
338 * @return ParameterScanner
339 * @throws Exception\InvalidArgumentException
341 public function getParameter($parameterNameOrInfoIndex)
345 if (is_int($parameterNameOrInfoIndex)) {
346 $info = $this->infos
[$parameterNameOrInfoIndex];
347 if ($info['type'] != 'parameter') {
348 throw new Exception\
InvalidArgumentException('Index of info offset is not about a parameter');
350 } elseif (is_string($parameterNameOrInfoIndex)) {
351 foreach ($this->infos
as $info) {
352 if ($info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) {
358 throw new Exception\
InvalidArgumentException('Index of info offset is not about a parameter');
362 $p = new ParameterScanner(
363 array_slice($this->tokens
, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart']),
364 $this->nameInformation
366 $p->setDeclaringFunction($this->name
);
367 $p->setDeclaringScannerFunction($this);
368 $p->setDeclaringClass($this->class);
369 $p->setDeclaringScannerClass($this->scannerClass
);
370 $p->setPosition($info['position']);
378 public function getBody()
385 public static function export()
390 public function __toString()
394 return var_export($this, true);
397 protected function scan()
399 if ($this->isScanned
) {
403 if (!$this->tokens
) {
404 throw new Exception\
RuntimeException('No tokens were provided');
411 $tokens = &$this->tokens
; // localize
412 $infos = &$this->infos
; // localize
416 $tokenContent = null;
424 $MACRO_TOKEN_ADVANCE = function () use (
432 static $lastTokenArray = null;
433 $tokenIndex = ($tokenIndex === null) ?
0 : $tokenIndex +
1;
434 if (!isset($tokens[$tokenIndex])) {
436 $tokenContent = false;
442 $token = $tokens[$tokenIndex];
443 if (is_string($token)) {
445 $tokenContent = $token;
446 $tokenLine = $tokenLine +
substr_count(
449 ); // adjust token line by last known newline count
451 list($tokenType, $tokenContent, $tokenLine) = $token;
456 $MACRO_INFO_START = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
457 $infos[$infoIndex] = array(
458 'type' => 'parameter',
459 'tokenStart' => $tokenIndex,
461 'lineStart' => $tokenLine,
462 'lineEnd' => $tokenLine,
464 'position' => $infoIndex +
1, // position is +1 of infoIndex
467 $MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
468 $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
469 $infos[$infoIndex]['lineEnd'] = $tokenLine;
476 * START FINITE STATE MACHINE FOR SCANNING TOKENS
480 $MACRO_TOKEN_ADVANCE();
484 $this->lineStart
= ($this->lineStart
) ?
: $tokenLine;
486 switch ($tokenType) {
488 $this->lineStart
= null;
489 if ($this->docComment
=== null && $this->name
=== null) {
490 $this->docComment
= $tokenContent;
492 goto SCANNER_CONTINUE_SIGNATURE
;
493 //goto (no break needed);
496 $this->isFinal
= true;
497 goto SCANNER_CONTINUE_SIGNATURE
;
498 //goto (no break needed);
501 $this->isAbstract
= true;
502 goto SCANNER_CONTINUE_SIGNATURE
;
503 //goto (no break needed);
507 goto SCANNER_CONTINUE_SIGNATURE
;
508 //goto (no break needed);
511 $this->setVisibility(T_PROTECTED
);
512 goto SCANNER_CONTINUE_SIGNATURE
;
513 //goto (no break needed);
516 $this->setVisibility(T_PRIVATE
);
517 goto SCANNER_CONTINUE_SIGNATURE
;
518 //goto (no break needed);
521 $this->isStatic
= true;
522 goto SCANNER_CONTINUE_SIGNATURE
;
523 //goto (no break needed);
528 if ($tokenType === T_STRING
&& $parentCount === 0) {
529 $this->name
= $tokenContent;
532 if ($parentCount === 1) {
533 if (!isset($infos[$infoIndex])) {
536 if ($tokenType === T_VARIABLE
) {
537 $infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
541 goto SCANNER_CONTINUE_SIGNATURE
;
542 //goto (no break needed);
546 switch ($tokenContent) {
548 if (!isset($infos[$infoIndex])) {
551 goto SCANNER_CONTINUE_SIGNATURE
;
552 //goto (no break needed);
555 goto SCANNER_CONTINUE_SIGNATURE
;
556 //goto (no break needed);
559 if ($parentCount > 0) {
560 goto SCANNER_CONTINUE_SIGNATURE
;
562 if ($parentCount === 0) {
564 $MACRO_INFO_ADVANCE();
568 goto SCANNER_CONTINUE_BODY
;
569 //goto (no break needed);
571 if ($parentCount === 1) {
572 $MACRO_INFO_ADVANCE();
574 goto SCANNER_CONTINUE_SIGNATURE
;
578 SCANNER_CONTINUE_SIGNATURE
:
580 if ($MACRO_TOKEN_ADVANCE() === false) {
585 SCANNER_CONTINUE_BODY
:
588 while ($MACRO_TOKEN_ADVANCE() !== false) {
589 if ($tokenContent == '}') {
592 if ($braceCount > 0) {
593 $this->body
.= $tokenContent;
595 if ($tokenContent == '{') {
598 $this->lineEnd
= $tokenLine;
603 $this->isScanned
= true;