PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/zendframework/zend-code/src/Scanner/MethodScanner.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 607 lines | 349 code | 98 blank | 160 comment | 39 complexity | e87fb04d25a87d5e75bfa0cfc39ff9dc MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  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
  8. */
  9. namespace Zend\Code\Scanner;
  10. use Zend\Code\Annotation\AnnotationManager;
  11. use Zend\Code\Exception;
  12. use Zend\Code\NameInformation;
  13. class MethodScanner implements ScannerInterface
  14. {
  15. /**
  16. * @var bool
  17. */
  18. protected $isScanned = false;
  19. /**
  20. * @var string
  21. */
  22. protected $docComment = null;
  23. /**
  24. * @var ClassScanner
  25. */
  26. protected $scannerClass = null;
  27. /**
  28. * @var string
  29. */
  30. protected $class = null;
  31. /**
  32. * @var string
  33. */
  34. protected $name = null;
  35. /**
  36. * @var int
  37. */
  38. protected $lineStart = null;
  39. /**
  40. * @var int
  41. */
  42. protected $lineEnd = null;
  43. /**
  44. * @var bool
  45. */
  46. protected $isFinal = false;
  47. /**
  48. * @var bool
  49. */
  50. protected $isAbstract = false;
  51. /**
  52. * @var bool
  53. */
  54. protected $isPublic = true;
  55. /**
  56. * @var bool
  57. */
  58. protected $isProtected = false;
  59. /**
  60. * @var bool
  61. */
  62. protected $isPrivate = false;
  63. /**
  64. * @var bool
  65. */
  66. protected $isStatic = false;
  67. /**
  68. * @var string
  69. */
  70. protected $body = '';
  71. /**
  72. * @var array
  73. */
  74. protected $tokens = array();
  75. /**
  76. * @var NameInformation
  77. */
  78. protected $nameInformation = null;
  79. /**
  80. * @var array
  81. */
  82. protected $infos = array();
  83. /**
  84. * @param array $methodTokens
  85. * @param NameInformation $nameInformation
  86. */
  87. public function __construct(array $methodTokens, NameInformation $nameInformation = null)
  88. {
  89. $this->tokens = $methodTokens;
  90. $this->nameInformation = $nameInformation;
  91. }
  92. /**
  93. * @param string $class
  94. * @return MethodScanner
  95. */
  96. public function setClass($class)
  97. {
  98. $this->class = (string) $class;
  99. return $this;
  100. }
  101. /**
  102. * @param ClassScanner $scannerClass
  103. * @return MethodScanner
  104. */
  105. public function setScannerClass(ClassScanner $scannerClass)
  106. {
  107. $this->scannerClass = $scannerClass;
  108. return $this;
  109. }
  110. /**
  111. * @return MethodScanner
  112. */
  113. public function getClassScanner()
  114. {
  115. return $this->scannerClass;
  116. }
  117. /**
  118. * @return string
  119. */
  120. public function getName()
  121. {
  122. $this->scan();
  123. return $this->name;
  124. }
  125. /**
  126. * @return int
  127. */
  128. public function getLineStart()
  129. {
  130. $this->scan();
  131. return $this->lineStart;
  132. }
  133. /**
  134. * @return int
  135. */
  136. public function getLineEnd()
  137. {
  138. $this->scan();
  139. return $this->lineEnd;
  140. }
  141. /**
  142. * @return string
  143. */
  144. public function getDocComment()
  145. {
  146. $this->scan();
  147. return $this->docComment;
  148. }
  149. /**
  150. * @param AnnotationManager $annotationManager
  151. * @return AnnotationScanner
  152. */
  153. public function getAnnotations(AnnotationManager $annotationManager)
  154. {
  155. if (($docComment = $this->getDocComment()) == '') {
  156. return false;
  157. }
  158. return new AnnotationScanner($annotationManager, $docComment, $this->nameInformation);
  159. }
  160. /**
  161. * @return bool
  162. */
  163. public function isFinal()
  164. {
  165. $this->scan();
  166. return $this->isFinal;
  167. }
  168. /**
  169. * @return bool
  170. */
  171. public function isAbstract()
  172. {
  173. $this->scan();
  174. return $this->isAbstract;
  175. }
  176. /**
  177. * @return bool
  178. */
  179. public function isPublic()
  180. {
  181. $this->scan();
  182. return $this->isPublic;
  183. }
  184. /**
  185. * @return bool
  186. */
  187. public function isProtected()
  188. {
  189. $this->scan();
  190. return $this->isProtected;
  191. }
  192. /**
  193. * @return bool
  194. */
  195. public function isPrivate()
  196. {
  197. $this->scan();
  198. return $this->isPrivate;
  199. }
  200. /**
  201. * @return bool
  202. */
  203. public function isStatic()
  204. {
  205. $this->scan();
  206. return $this->isStatic;
  207. }
  208. /**
  209. * Override the given name for a method, this is necessary to
  210. * support traits.
  211. *
  212. * @param $name
  213. * @return self
  214. */
  215. public function setName($name)
  216. {
  217. $this->name = $name;
  218. return $this;
  219. }
  220. /**
  221. * Visibility must be of T_PUBLIC, T_PRIVATE or T_PROTECTED
  222. * Needed to support traits
  223. *
  224. * @param $visibility T_PUBLIC | T_PRIVATE | T_PROTECTED
  225. * @return self
  226. * @throws \Zend\Code\Exception
  227. */
  228. public function setVisibility($visibility)
  229. {
  230. switch (strtolower($visibility)) {
  231. case T_PUBLIC:
  232. $this->isPublic = true;
  233. $this->isPrivate = false;
  234. $this->isProtected = false;
  235. break;
  236. case T_PRIVATE:
  237. $this->isPublic = false;
  238. $this->isPrivate = true;
  239. $this->isProtected = false;
  240. break;
  241. case T_PROTECTED:
  242. $this->isPublic = false;
  243. $this->isPrivate = false;
  244. $this->isProtected = true;
  245. break;
  246. default:
  247. throw new Exception("Invalid visibility argument passed to setVisibility.");
  248. }
  249. return $this;
  250. }
  251. /**
  252. * @return int
  253. */
  254. public function getNumberOfParameters()
  255. {
  256. return count($this->getParameters());
  257. }
  258. /**
  259. * @param bool $returnScanner
  260. * @return array
  261. */
  262. public function getParameters($returnScanner = false)
  263. {
  264. $this->scan();
  265. $return = array();
  266. foreach ($this->infos as $info) {
  267. if ($info['type'] != 'parameter') {
  268. continue;
  269. }
  270. if (!$returnScanner) {
  271. $return[] = $info['name'];
  272. } else {
  273. $return[] = $this->getParameter($info['name']);
  274. }
  275. }
  276. return $return;
  277. }
  278. /**
  279. * @param int|string $parameterNameOrInfoIndex
  280. * @return ParameterScanner
  281. * @throws Exception\InvalidArgumentException
  282. */
  283. public function getParameter($parameterNameOrInfoIndex)
  284. {
  285. $this->scan();
  286. if (is_int($parameterNameOrInfoIndex)) {
  287. $info = $this->infos[$parameterNameOrInfoIndex];
  288. if ($info['type'] != 'parameter') {
  289. throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter');
  290. }
  291. } elseif (is_string($parameterNameOrInfoIndex)) {
  292. foreach ($this->infos as $info) {
  293. if ($info['type'] === 'parameter' && $info['name'] === $parameterNameOrInfoIndex) {
  294. break;
  295. }
  296. unset($info);
  297. }
  298. if (!isset($info)) {
  299. throw new Exception\InvalidArgumentException('Index of info offset is not about a parameter');
  300. }
  301. }
  302. $p = new ParameterScanner(
  303. array_slice($this->tokens, $info['tokenStart'], $info['tokenEnd'] - $info['tokenStart']),
  304. $this->nameInformation
  305. );
  306. $p->setDeclaringFunction($this->name);
  307. $p->setDeclaringScannerFunction($this);
  308. $p->setDeclaringClass($this->class);
  309. $p->setDeclaringScannerClass($this->scannerClass);
  310. $p->setPosition($info['position']);
  311. return $p;
  312. }
  313. /**
  314. * @return string
  315. */
  316. public function getBody()
  317. {
  318. $this->scan();
  319. return $this->body;
  320. }
  321. public static function export()
  322. {
  323. // @todo
  324. }
  325. public function __toString()
  326. {
  327. $this->scan();
  328. return var_export($this, true);
  329. }
  330. protected function scan()
  331. {
  332. if ($this->isScanned) {
  333. return;
  334. }
  335. if (!$this->tokens) {
  336. throw new Exception\RuntimeException('No tokens were provided');
  337. }
  338. /**
  339. * Variables & Setup
  340. */
  341. $tokens = &$this->tokens; // localize
  342. $infos = &$this->infos; // localize
  343. $tokenIndex = null;
  344. $token = null;
  345. $tokenType = null;
  346. $tokenContent = null;
  347. $tokenLine = null;
  348. $infoIndex = 0;
  349. $parentCount = 0;
  350. /*
  351. * MACRO creation
  352. */
  353. $MACRO_TOKEN_ADVANCE = function () use (
  354. &$tokens,
  355. &$tokenIndex,
  356. &$token,
  357. &$tokenType,
  358. &$tokenContent,
  359. &$tokenLine
  360. ) {
  361. static $lastTokenArray = null;
  362. $tokenIndex = ($tokenIndex === null) ? 0 : $tokenIndex + 1;
  363. if (!isset($tokens[$tokenIndex])) {
  364. $token = false;
  365. $tokenContent = false;
  366. $tokenType = false;
  367. $tokenLine = false;
  368. return false;
  369. }
  370. $token = $tokens[$tokenIndex];
  371. if (is_string($token)) {
  372. $tokenType = null;
  373. $tokenContent = $token;
  374. $tokenLine = $tokenLine + substr_count(
  375. $lastTokenArray[1],
  376. "\n"
  377. ); // adjust token line by last known newline count
  378. } else {
  379. list($tokenType, $tokenContent, $tokenLine) = $token;
  380. }
  381. return $tokenIndex;
  382. };
  383. $MACRO_INFO_START = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
  384. $infos[$infoIndex] = array(
  385. 'type' => 'parameter',
  386. 'tokenStart' => $tokenIndex,
  387. 'tokenEnd' => null,
  388. 'lineStart' => $tokenLine,
  389. 'lineEnd' => $tokenLine,
  390. 'name' => null,
  391. 'position' => $infoIndex + 1, // position is +1 of infoIndex
  392. );
  393. };
  394. $MACRO_INFO_ADVANCE = function () use (&$infoIndex, &$infos, &$tokenIndex, &$tokenLine) {
  395. $infos[$infoIndex]['tokenEnd'] = $tokenIndex;
  396. $infos[$infoIndex]['lineEnd'] = $tokenLine;
  397. $infoIndex++;
  398. return $infoIndex;
  399. };
  400. /**
  401. * START FINITE STATE MACHINE FOR SCANNING TOKENS
  402. */
  403. // Initialize token
  404. $MACRO_TOKEN_ADVANCE();
  405. SCANNER_TOP:
  406. $this->lineStart = ($this->lineStart) ? : $tokenLine;
  407. switch ($tokenType) {
  408. case T_DOC_COMMENT:
  409. $this->lineStart = null;
  410. if ($this->docComment === null && $this->name === null) {
  411. $this->docComment = $tokenContent;
  412. }
  413. goto SCANNER_CONTINUE_SIGNATURE;
  414. //goto (no break needed);
  415. case T_FINAL:
  416. $this->isFinal = true;
  417. goto SCANNER_CONTINUE_SIGNATURE;
  418. //goto (no break needed);
  419. case T_ABSTRACT:
  420. $this->isAbstract = true;
  421. goto SCANNER_CONTINUE_SIGNATURE;
  422. //goto (no break needed);
  423. case T_PUBLIC:
  424. // use defaults
  425. goto SCANNER_CONTINUE_SIGNATURE;
  426. //goto (no break needed);
  427. case T_PROTECTED:
  428. $this->setVisibility(T_PROTECTED);
  429. goto SCANNER_CONTINUE_SIGNATURE;
  430. //goto (no break needed);
  431. case T_PRIVATE:
  432. $this->setVisibility(T_PRIVATE);
  433. goto SCANNER_CONTINUE_SIGNATURE;
  434. //goto (no break needed);
  435. case T_STATIC:
  436. $this->isStatic = true;
  437. goto SCANNER_CONTINUE_SIGNATURE;
  438. //goto (no break needed);
  439. case T_VARIABLE:
  440. case T_STRING:
  441. if ($tokenType === T_STRING && $parentCount === 0) {
  442. $this->name = $tokenContent;
  443. }
  444. if ($parentCount === 1) {
  445. if (!isset($infos[$infoIndex])) {
  446. $MACRO_INFO_START();
  447. }
  448. if ($tokenType === T_VARIABLE) {
  449. $infos[$infoIndex]['name'] = ltrim($tokenContent, '$');
  450. }
  451. }
  452. goto SCANNER_CONTINUE_SIGNATURE;
  453. //goto (no break needed);
  454. case null:
  455. switch ($tokenContent) {
  456. case '&':
  457. if (!isset($infos[$infoIndex])) {
  458. $MACRO_INFO_START();
  459. }
  460. goto SCANNER_CONTINUE_SIGNATURE;
  461. //goto (no break needed);
  462. case '(':
  463. $parentCount++;
  464. goto SCANNER_CONTINUE_SIGNATURE;
  465. //goto (no break needed);
  466. case ')':
  467. $parentCount--;
  468. if ($parentCount > 0) {
  469. goto SCANNER_CONTINUE_SIGNATURE;
  470. }
  471. if ($parentCount === 0) {
  472. if ($infos) {
  473. $MACRO_INFO_ADVANCE();
  474. }
  475. $context = 'body';
  476. }
  477. goto SCANNER_CONTINUE_BODY;
  478. //goto (no break needed);
  479. case ',':
  480. if ($parentCount === 1) {
  481. $MACRO_INFO_ADVANCE();
  482. }
  483. goto SCANNER_CONTINUE_SIGNATURE;
  484. }
  485. }
  486. SCANNER_CONTINUE_SIGNATURE:
  487. if ($MACRO_TOKEN_ADVANCE() === false) {
  488. goto SCANNER_END;
  489. }
  490. goto SCANNER_TOP;
  491. SCANNER_CONTINUE_BODY:
  492. $braceCount = 0;
  493. while ($MACRO_TOKEN_ADVANCE() !== false) {
  494. if ($tokenContent == '}') {
  495. $braceCount--;
  496. }
  497. if ($braceCount > 0) {
  498. $this->body .= $tokenContent;
  499. }
  500. if ($tokenContent == '{') {
  501. $braceCount++;
  502. }
  503. $this->lineEnd = $tokenLine;
  504. }
  505. SCANNER_END:
  506. $this->isScanned = true;
  507. return;
  508. }
  509. }