PageRenderTime 27ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/mfairchild365/zf2
PHP | 332 lines | 267 code | 56 blank | 9 comment | 41 complexity | b9b9eccc32310dcdca02d12df07b774e MD5 | raw file
  1. <?php
  2. namespace Zend\Code\Scanner;
  3. use Zend\Code\Scanner,
  4. Zend\Code\Exception;
  5. class MethodScanner implements Scanner
  6. {
  7. protected $isScanned = false;
  8. protected $scannerClass = null;
  9. protected $class = null;
  10. protected $namespace = null;
  11. protected $uses = array();
  12. protected $name = null;
  13. protected $isFinal = false;
  14. protected $isAbstract = false;
  15. protected $isPublic = true;
  16. protected $isProtected = false;
  17. protected $isPrivate = false;
  18. protected $isStatic = false;
  19. protected $tokens = array();
  20. protected $infos = array();
  21. public function __construct(array $methodTokens, $namespace = null, array $uses = array())
  22. {
  23. $this->tokens = $methodTokens;
  24. $this->namespace = $namespace;
  25. $this->uses = $uses;
  26. }
  27. public function setClass($class)
  28. {
  29. $this->class = $class;
  30. }
  31. public function setScannerClass(ClassScanner $scannerClass)
  32. {
  33. $this->scannerClass = $scannerClass;
  34. }
  35. public function getClassScanner()
  36. {
  37. return $this->scannerClass;
  38. }
  39. protected function scan()
  40. {
  41. if ($this->isScanned) {
  42. return;
  43. }
  44. if (!$this->tokens) {
  45. throw new Exception\RuntimeException('No tokens were provided');
  46. }
  47. $fastForward = 0;
  48. $tokenIndex = 0;
  49. $this->scanMethodInfo($tokenIndex, $fastForward);
  50. if ($fastForward) {
  51. $tokenIndex += $fastForward - 1;
  52. $fastForward = 0;
  53. }
  54. // advance to first paren
  55. while ($this->tokens[$tokenIndex] != '(') {
  56. $tokenIndex++;
  57. }
  58. $this->scanParameters($tokenIndex, $fastForward);
  59. $this->isScanned = true;
  60. }
  61. protected function scanMethodInfo($tokenIndex, &$fastForward)
  62. {
  63. while (true) {
  64. $token = $this->tokens[$tokenIndex];
  65. // BREAK ON
  66. if (is_string($token) && $token == '(') {
  67. break;
  68. }
  69. // ANALYZE
  70. if (is_string($token)) {
  71. continue;
  72. }
  73. switch ($token[0]) {
  74. case T_FINAL:
  75. $this->isFinal = true;
  76. continue;
  77. case T_ABSTRACT:
  78. $this->isAbstract = true;
  79. continue;
  80. case T_PUBLIC:
  81. continue;
  82. case T_PROTECTED:
  83. $this->isProtected = true;
  84. $this->isPublic = false;
  85. continue;
  86. case T_PRIVATE:
  87. $this->isPrivate = true;
  88. $this->isPublic = false;
  89. continue;
  90. case T_STATIC:
  91. $this->isStatic = true;
  92. continue;
  93. case T_STRING:
  94. $this->name = $token[1];
  95. continue;
  96. }
  97. $fastForward++;
  98. $tokenIndex++;
  99. }
  100. }
  101. protected function scanParameters($tokenIndex, &$fastForward)
  102. {
  103. // first token is paren let loop increase
  104. $parenCount = 1;
  105. $info = null;
  106. $position = 0;
  107. while (true) {
  108. $tokenIndex++;
  109. $fastForward++;
  110. $token = $this->tokens[$tokenIndex];
  111. // BREAK ON
  112. if ($parenCount == 1 && is_string($token) && $token == ')') {
  113. if ($info) {
  114. $info['tokenEnd'] = $tokenIndex - 1;
  115. $this->infos[] = $info;
  116. }
  117. break;
  118. }
  119. // ANALYZE
  120. // gather line information if we can
  121. if (!isset($info)) {
  122. $info = array(
  123. 'type' => 'parameter',
  124. 'tokenStart' => $tokenIndex,
  125. 'tokenEnd' => null,
  126. 'lineStart' => $token[2],
  127. 'lineEnd' => $token[2],
  128. 'name' => null,
  129. 'position' => ++$position,
  130. );
  131. }
  132. if (is_array($token) && isset($info)) {
  133. $info['lineEnd'] = $token[2];
  134. }
  135. if (is_array($token) && $token[0] === T_WHITESPACE) {
  136. continue;
  137. }
  138. if (is_string($token)) {
  139. if ($token == '(') {
  140. $parenCount++;
  141. }
  142. if ($token == ')') {
  143. $parenCount--;
  144. }
  145. if ($parenCount !== 1) {
  146. continue;
  147. }
  148. }
  149. if (isset($info) && is_string($token) && $token == ',') {
  150. $info['tokenEnd'] = $tokenIndex - 1;
  151. $this->infos[] = $info;
  152. unset($info);
  153. }
  154. if (is_array($token) && $token[0] === T_VARIABLE) {
  155. $info['name'] = ltrim($token[1], '$');
  156. }
  157. }
  158. }
  159. public function getName()
  160. {
  161. $this->scan();
  162. return $this->name;
  163. }
  164. public function isFinal()
  165. {
  166. $this->scan();
  167. return $this->isFinal;
  168. }
  169. public function isAbstract()
  170. {
  171. $this->scan();
  172. return $this->isAbstract;
  173. }
  174. public function isPublic()
  175. {
  176. $this->scan();
  177. return $this->isPublic;
  178. }
  179. public function isProtected()
  180. {
  181. $this->scan();
  182. return $this->isProtected;
  183. }
  184. public function isPrivate()
  185. {
  186. $this->scan();
  187. return $this->isPrivate;
  188. }
  189. public function isStatic()
  190. {
  191. $this->scan();
  192. return $this->isStatic;
  193. }
  194. public function getNumberOfParameters()
  195. {
  196. return count($this->getParameters());
  197. }
  198. public function getParameters($returnScanner = false)
  199. {
  200. $this->scan();
  201. $return = array();
  202. foreach ($this->infos as $info) {
  203. if ($info['type'] != 'parameter') {
  204. continue;
  205. }
  206. if (!$returnScanner) {
  207. $return[] = $info['name'];
  208. } else {
  209. $return[] = $this->getParameter($info['name'], $returnScanner);
  210. }
  211. }
  212. return $return;
  213. }
  214. public function getParameter($parameterNameOrInfoIndex, $returnScanner = 'Zend\Code\Scanner\ParameterScanner')
  215. {
  216. $this->scan();
  217. // process the class requested
  218. // Static for performance reasons
  219. static $baseScannerClass = 'Zend\Code\Scanner\ParameterScanner';
  220. if ($returnScanner !== $baseScannerClass) {
  221. if (!is_string($returnScanner)) {
  222. $returnScanner = $baseScannerClass;
  223. }
  224. $returnScanner = ltrim($returnScanner, '\\');
  225. if ($returnScanner !== $baseScannerClass
  226. && !is_subclass_of($returnScanner, $baseScannerClass)
  227. ) {
  228. throw new Exception\RuntimeException(sprintf(
  229. 'Class must be or extend "%s"', $baseScannerClass
  230. ));
  231. }
  232. }
  233. if (is_int($parameterNameOrInfoIndex)) {
  234. $info = $this->infos[$parameterNameOrInfoIndex];
  235. if ($info['type'] != 'parameter') {
  236. throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter');
  237. }
  238. } elseif (is_string($parameterNameOrInfoIndex)) {
  239. $methodFound = false;
  240. foreach ($this->infos as $infoIndex => $info) {
  241. if ($info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) {
  242. $methodFound = true;
  243. break;
  244. }
  245. }
  246. if (!$methodFound) {
  247. return false;
  248. }
  249. }
  250. $p = new $returnScanner(
  251. array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart'] + 1),
  252. $this->namespace,
  253. $this->uses
  254. );
  255. $p->setDeclaringFunction($this->name);
  256. $p->setDeclaringScannerFunction($this);
  257. $p->setDeclaringClass($this->class);
  258. $p->setDeclaringScannerClass($this->scannerClass);
  259. $p->setPosition($info['position']);
  260. return $p;
  261. }
  262. public static function export()
  263. {
  264. // @todo
  265. }
  266. public function __toString()
  267. {
  268. $this->scan();
  269. return var_export($this, true);
  270. }
  271. }