/library/Zend/Code/Scanner/MethodScanner.php

https://github.com/brazza/zf2 · PHP · 342 lines · 271 code · 56 blank · 15 comment · 30 complexity · 7d6d6f364c9b68ab09f07fa200ca5458 MD5 · raw file

  1. <?php
  2. namespace Zend\Code\Scanner;
  3. use Zend\Code\Scanner,
  4. Zend\Code\NameInformation,
  5. Zend\Code\Exception,
  6. Zend\Code\Annotation;
  7. class MethodScanner implements Scanner
  8. {
  9. protected $isScanned = false;
  10. protected $docComment = null;
  11. protected $scannerClass = null;
  12. protected $class = null;
  13. protected $name = null;
  14. protected $isFinal = false;
  15. protected $isAbstract = false;
  16. protected $isPublic = true;
  17. protected $isProtected = false;
  18. protected $isPrivate = false;
  19. protected $isStatic = false;
  20. protected $tokens = array();
  21. protected $nameInformation = null;
  22. protected $infos = array();
  23. public function __construct(array $methodTokens, NameInformation $nameInformation = null)
  24. {
  25. $this->tokens = $methodTokens;
  26. $this->nameInformation = $nameInformation;
  27. }
  28. public function setClass($class)
  29. {
  30. $this->class = $class;
  31. }
  32. public function setScannerClass(ClassScanner $scannerClass)
  33. {
  34. $this->scannerClass = $scannerClass;
  35. }
  36. public function getClassScanner()
  37. {
  38. return $this->scannerClass;
  39. }
  40. public function getName()
  41. {
  42. $this->scan();
  43. return $this->name;
  44. }
  45. public function getDocComment()
  46. {
  47. $this->scan();
  48. return $this->docComment;
  49. }
  50. /**
  51. * @return AnnotationCollection
  52. */
  53. public function getAnnotations(Annotation\AnnotationManager $annotationManager)
  54. {
  55. if (($docComment = $this->getDocComment()) == '') {
  56. return false;
  57. }
  58. return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
  59. }
  60. public function isFinal()
  61. {
  62. $this->scan();
  63. return $this->isFinal;
  64. }
  65. public function isAbstract()
  66. {
  67. $this->scan();
  68. return $this->isAbstract;
  69. }
  70. public function isPublic()
  71. {
  72. $this->scan();
  73. return $this->isPublic;
  74. }
  75. public function isProtected()
  76. {
  77. $this->scan();
  78. return $this->isProtected;
  79. }
  80. public function isPrivate()
  81. {
  82. $this->scan();
  83. return $this->isPrivate;
  84. }
  85. public function isStatic()
  86. {
  87. $this->scan();
  88. return $this->isStatic;
  89. }
  90. public function getNumberOfParameters()
  91. {
  92. return count($this->getParameters());
  93. }
  94. public function getParameters($returnScanner = false)
  95. {
  96. $this->scan();
  97. $return = array();
  98. foreach ($this->infos as $info) {
  99. if ($info['type'] != 'parameter') {
  100. continue;
  101. }
  102. if (!$returnScanner) {
  103. $return[] = $info['name'];
  104. } else {
  105. $return[] = $this->getParameter($info['name']);
  106. }
  107. }
  108. return $return;
  109. }
  110. public function getParameter($parameterNameOrInfoIndex)
  111. {
  112. $this->scan();
  113. if (is_int($parameterNameOrInfoIndex)) {
  114. $info = $this->infos[$parameterNameOrInfoIndex];
  115. if ($info['type'] != 'parameter') {
  116. throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter');
  117. }
  118. } elseif (is_string($parameterNameOrInfoIndex)) {
  119. foreach ($this->infos as $infoIndex => $info) {
  120. if ($info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) {
  121. break;
  122. }
  123. unset($info);
  124. }
  125. if (!isset($info)){
  126. throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter');
  127. }
  128. }
  129. $p = new ParameterScanner(
  130. array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart']),
  131. $this->nameInformation
  132. );
  133. $p->setDeclaringFunction($this->name);
  134. $p->setDeclaringScannerFunction($this);
  135. $p->setDeclaringClass($this->class);
  136. $p->setDeclaringScannerClass($this->scannerClass);
  137. $p->setPosition($info['position']);
  138. return $p;
  139. }
  140. public static function export()
  141. {
  142. // @todo
  143. }
  144. public function __toString()
  145. {
  146. $this->scan();
  147. return var_export($this, true);
  148. }
  149. protected function scan()
  150. {
  151. if ($this->isScanned) {
  152. return;
  153. }
  154. if (!$this->tokens) {
  155. throw new Exception\RuntimeException('No tokens were provided');
  156. }
  157. /**
  158. * Variables & Setup
  159. */
  160. $tokens = &$this->tokens; // localize
  161. $infos = &$this->infos; // localize
  162. $tokenIndex = null;
  163. $token = null;
  164. $tokenType = null;
  165. $tokenContent = null;
  166. $tokenLine = null;
  167. $infoIndex = 0;
  168. $parenCount = 0;
  169. /**
  170. * MACRO creation
  171. */
  172. $MACRO_TOKEN_ADVANCE = function() use (&$tokens, &$tokenIndex, &$token, &$tokenType, &$tokenContent, &$tokenLine) {
  173. $tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex+1;
  174. if (!isset($tokens[$tokenIndex])) {
  175. $token = false;
  176. $tokenContent = false;
  177. $tokenType = false;
  178. $tokenLine = false;
  179. return false;
  180. }
  181. $token = $tokens[$tokenIndex];
  182. if (is_string($token)) {
  183. $tokenType = null;
  184. $tokenContent = $token;
  185. } else {
  186. list($tokenType, $tokenContent, $tokenLine) = $token;
  187. }
  188. return $tokenIndex;
  189. };
  190. $MACRO_INFO_START = function() use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
  191. $infos[$infoIndex] = array(
  192. 'type' => 'parameter',
  193. 'tokenStart' => $tokenIndex,
  194. 'tokenEnd' => null,
  195. 'lineStart' => $tokenLine,
  196. 'lineEnd' => $tokenLine,
  197. 'name' => null,
  198. 'position' => $infoIndex + 1, // position is +1 of infoIndex
  199. );
  200. };
  201. $MACRO_INFO_ADVANCE = function() use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
  202. $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
  203. $infos[$infoIndex]['lineEnd'] = $tokenLine;
  204. $infoIndex++;
  205. return $infoIndex;
  206. };
  207. /**
  208. * START FINITE STATE MACHINE FOR SCANNING TOKENS
  209. */
  210. // Initialize token
  211. $MACRO_TOKEN_ADVANCE();
  212. SCANNER_TOP:
  213. switch ($tokenType) {
  214. case T_DOC_COMMENT:
  215. if ($this->docComment === null && $this->name === null) {
  216. $this->docComment = $tokenContent;
  217. }
  218. goto SCANNER_CONTINUE;
  219. case T_FINAL:
  220. $this->isFinal = true;
  221. goto SCANNER_CONTINUE;
  222. case T_ABSTRACT:
  223. $this->isAbstract = true;
  224. goto SCANNER_CONTINUE;
  225. case T_PUBLIC:
  226. // use defaults
  227. goto SCANNER_CONTINUE;
  228. case T_PROTECTED:
  229. $this->isProtected = true;
  230. $this->isPublic = false;
  231. goto SCANNER_CONTINUE;
  232. case T_PRIVATE:
  233. $this->isPrivate = true;
  234. $this->isPublic = false;
  235. goto SCANNER_CONTINUE;
  236. case T_STATIC:
  237. $this->isStatic = true;
  238. goto SCANNER_CONTINUE;
  239. case T_VARIABLE:
  240. case T_STRING:
  241. if ($tokenType === T_STRING && $parenCount === 0) {
  242. $this->name = $tokenContent;
  243. }
  244. if ($parenCount === 1) {
  245. if (!isset($infos[$infoIndex])) {
  246. $MACRO_INFO_START();
  247. }
  248. if ($tokenType === T_VARIABLE) {
  249. $infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
  250. }
  251. }
  252. goto SCANNER_CONTINUE;
  253. case null:
  254. switch ($tokenContent) {
  255. case '&':
  256. if (!isset($infos[$infoIndex])) {
  257. $MACRO_INFO_START();
  258. }
  259. goto SCANNER_CONTINUE;
  260. case '(':
  261. $parenCount++;
  262. goto SCANNER_CONTINUE;
  263. case ')':
  264. $parenCount--;
  265. if ($parenCount === 0) {
  266. $MACRO_INFO_ADVANCE();
  267. goto SCANNER_END;
  268. }
  269. goto SCANNER_CONTINUE;
  270. case ',':
  271. if ($parenCount === 1) {
  272. $MACRO_INFO_ADVANCE();
  273. }
  274. goto SCANNER_CONTINUE;
  275. }
  276. }
  277. SCANNER_CONTINUE:
  278. if ($MACRO_TOKEN_ADVANCE() === false) {
  279. goto SCANNER_END;
  280. }
  281. goto SCANNER_TOP;
  282. SCANNER_END:
  283. $this->isScanned = true;
  284. return;
  285. }
  286. }