PageRenderTime 61ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/web/vendors/PHP/DocBlockGenerator/Tokens.php

https://bitbucket.org/bestteam/expenses
PHP | 481 lines | 199 code | 43 blank | 239 comment | 26 complexity | 143e93d3454bdc37d1e73e4aad22269c MD5 | raw file
Possible License(s): Apache-2.0
  1. <?php
  2. /**
  3. * DocBlock Generator
  4. *
  5. * PHP version 5
  6. *
  7. * All rights reserved.
  8. * Redistribution and use in source and binary forms, with or without modification,
  9. * are permitted provided that the following conditions are met:
  10. * + Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. * + Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation and/or
  14. * other materials provided with the distribution.
  15. * + The names of its contributors may not be used to endorse or
  16. * promote products derived from this software without specific prior written permission.
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  21. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  22. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  23. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  24. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  25. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  26. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * @category PHP
  30. * @package PHP_DocBlockGenerator
  31. * @author Michel Corne <mcorne@yahoo.com>
  32. * @copyright 2007 Michel Corne
  33. * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  34. * @version SVN: $Id: Tokens.php 31 2007-09-13 10:21:01Z mcorne $
  35. * @link http://pear.php.net/package/PHP_DocBlockGenerator
  36. */
  37. require_once 'PHP/DocBlockGenerator/Block.php';
  38. require_once 'PHP/CompatInfo.php';
  39. /**
  40. * Extraction of the PHP objects/tokens of the source code and creation of the DocBlocks
  41. *
  42. * @category PHP
  43. * @package PHP_DocBlockGenerator
  44. * @author Michel Corne <mcorne@yahoo.com>
  45. * @copyright 2007 Michel Corne
  46. * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  47. * @version Release: @package_version@
  48. * @link http://pear.php.net/package/PHP_DocBlockGenerator
  49. */
  50. class PHP_DocBlockGenerator_Tokens
  51. {
  52. /**
  53. * The PHP_DocBlockGenerator_Block instance
  54. *
  55. * @var object
  56. * @access private
  57. */
  58. private $block;
  59. /**
  60. * The source code End-Of-Line character
  61. *
  62. * EOL = "\r\n" for DOS/Windows, "\r" for MAC, "\n" for Unix
  63. *
  64. * @var string
  65. * @access public
  66. */
  67. public $eol;
  68. /**
  69. * Flag indicating if the current token has a DocBlock or not
  70. *
  71. * @var boolean
  72. * @access public
  73. */
  74. public $hasBlock;
  75. /**
  76. * The current token information, including the token type, access type...
  77. *
  78. * @var array
  79. * @access public
  80. */
  81. public $id;
  82. /**
  83. * Flag indicating if the current token is within a class
  84. *
  85. * @var integer
  86. * @access public
  87. */
  88. public $inClass;
  89. /**
  90. * Flag indicating if the class is an interface
  91. *
  92. * @var boolean
  93. * @access public
  94. */
  95. public $isInterface;
  96. /**
  97. * The none relevant PHP code tokens
  98. *
  99. * @var array
  100. * @access private
  101. */
  102. private $noPHPCode = array(// /
  103. T_WHITESPACE, T_ENCAPSED_AND_WHITESPACE, // spaces
  104. T_DOC_COMMENT, T_COMMENT, // comments
  105. T_INLINE_HTML, // none PHP code
  106. );
  107. /**
  108. * Source code tokens excluding none relevant PHP code tokens
  109. *
  110. * @var array
  111. * @access private
  112. */
  113. private $phpTokens = array();
  114. /**
  115. * The file PHP version
  116. *
  117. * @var string
  118. * @access public
  119. */
  120. public $phpVersion = '';
  121. /**
  122. * Source code tokens
  123. *
  124. * @var array
  125. * @access private
  126. */
  127. private $tokens = array();
  128. /**
  129. * The class constructor
  130. *
  131. * @return void
  132. * @access public
  133. */
  134. public function __construct()
  135. {
  136. $this->block = new PHP_DocBlockGenerator_Block($this);
  137. $this->info = new PHP_CompatInfo('null');
  138. }
  139. /**
  140. * Gets the current token
  141. *
  142. * @param integer $id the token identification number
  143. * @return array the token type and value, false if invalid ID
  144. * @access public
  145. */
  146. public function get($id)
  147. {
  148. return $this->isValid($id)? $this->tokens[$id] : false;
  149. }
  150. /**
  151. * Gets all the source code tokens and tidies them
  152. *
  153. * @param string $data the source code
  154. * @return boolean true on success, false on failure
  155. * @access private
  156. */
  157. private function getAll($data)
  158. {
  159. // extracts the tokens, tidies the tokens, extracts the PHP code only tokens
  160. $this->tokens = token_get_all($data) and array_walk($this->tokens, array($this, 'tidy')) and
  161. $this->phpTokens = array_filter($this->tokens, array($this, 'isPHPCode'));
  162. // /
  163. // dump of all the tokens: un-comment for debugging purposes only
  164. //file_put_contents('tokens.txt', var_export($this->tokens, true));
  165. // /
  166. return (bool)$this->tokens;
  167. }
  168. /**
  169. * Determines the source code End Of Line character
  170. *
  171. * EOL = "\r\n" for DOS/Windows, "\r" for MAC, "\n" for Unix
  172. *
  173. * @access private
  174. */
  175. private function getEOL($data)
  176. {
  177. if (strpos($data, "\r\n") !== false) { // DOS/Windows EOL
  178. $this->eol = "\r\n";
  179. } else if (strpos($data, "\r") !== false) { // MAC EOL
  180. $this->eol = "\r";
  181. } else { // Unix EOL
  182. $this->eol = "\n";
  183. }
  184. }
  185. /**
  186. * Verifies that the token is a valid source code token
  187. *
  188. * @param integer $id the token identification number
  189. * @return boolean true if valid, false otherwise
  190. * @access private
  191. */
  192. private function isValid($id)
  193. {
  194. return isset($this->tokens[$id]);
  195. }
  196. /**
  197. * Checks if the token is relevant PHP code, excluding spaces and comments.
  198. *
  199. * This is an array_filter() callback function.
  200. *
  201. * @param array $token the token
  202. * @return boolean true if relevant PHP code, false otherwise
  203. * @access private
  204. */
  205. private function isPHPCode($token)
  206. {
  207. return !in_array($token['type'], $this->noPHPCode);
  208. }
  209. /**
  210. * Processes the source code tokens
  211. *
  212. * Gets all the source code tokens. Determines the source code EOL.
  213. * Determines the file PHP version. Initializes the Page-level tags.
  214. * Parses the file tokens and creates their DocBlocks.
  215. * Re-assembles all the tokens with their DocBlocks.
  216. *
  217. * @param string $data the source code
  218. * @param array $param the tags/parameters values
  219. * @return boolean true on success, false on failure
  220. * @access public
  221. */
  222. public function process($data, $param)
  223. {
  224. // get all the tokens
  225. if ($result = $this->getAll($data)) {
  226. // determines the source code EOL
  227. $this->getEOL($data);
  228. // extracts all the tokens
  229. $allTokens = $this->slice();
  230. // initializes the Page-level tags
  231. $this->block->init($param);
  232. $this->hasBlock = 0;
  233. $this->id = array();
  234. $this->inClass = null;
  235. $this->isInterface = false;
  236. $inFunct = null;
  237. $openTagID = null;
  238. $isPageBlock = false;
  239. foreach($this->tokens as $id => $token) {
  240. $value = $token['value'];
  241. switch ($type = $token['type']) {
  242. case '{': // class or function opening curly brace
  243. // note: none matching open and close curly braces will cause issues
  244. case T_CURLY_OPEN:
  245. case T_DOLLAR_OPEN_CURLY_BRACES: // ${
  246. // counting braces within the function, and the class
  247. is_null($inFunct) or $inFunct++;
  248. is_null($this->inClass) or $this->inClass++;
  249. break;
  250. case '}': // class or function closing curly brace
  251. // reached end of the function or class
  252. is_null($inFunct) or --$inFunct or $inFunct = null;
  253. is_null($this->inClass) or --$this->inClass or
  254. $this->inClass = null or $this->isInterface = false;
  255. break;
  256. case T_ABSTRACT: // abstract, class or function abstraction
  257. case T_FINAL: // final class or function
  258. $this->id[$type] = $id;
  259. break;
  260. case T_CONST: // const
  261. // sets the const DocBlock
  262. is_null($this->inClass) or $this->block->setConst($id);
  263. break;
  264. case T_CONSTANT_ENCAPSED_STRING: // "foo" or 'bar' string syntax
  265. // sets the include DocBlock
  266. isset($this->id[T_INCLUDE]) and $this->block->build($this->id[T_INCLUDE]);
  267. break;
  268. case T_DOC_COMMENT: // /** */ PHPDoc style comments (PHP 5 only)
  269. // spots the page block, realigns the DocBlock tags
  270. $this->hasBlock = true;
  271. $isPageBlock or $isPageBlock = (strpos($value, '@package') !== false);
  272. $this->block->realign($id, $value);
  273. break;
  274. case T_FUNCTION: // function or cfunction functions
  275. $inFunct = 0;
  276. $this->block->setFunction($id); // sets function DocBlock
  277. break;
  278. case T_INCLUDE: // include()
  279. case T_INCLUDE_ONCE: // include_once()
  280. case T_REQUIRE: // require()
  281. case T_REQUIRE_ONCE: // require_once()
  282. $type = T_INCLUDE;
  283. case T_GLOBAL: // global variable scope
  284. // only capturing includes and globals outside of classes and functions
  285. is_null($this->inClass) and is_null($inFunct) and $this->id[$type] = $id;
  286. break;
  287. case T_INTERFACE: // interface, Object Interface
  288. $this->isInterface = true;
  289. case T_CLASS: // class, classes and objects
  290. $this->inClass = 0;
  291. $this->block->setClass($id);
  292. break;
  293. case T_OPEN_TAG: // <?php, <? or <%
  294. $openTagID = $id;
  295. break;
  296. case T_PRIVATE: // private classes and objects. PHP 5 only.
  297. case T_PROTECTED: // protected classes and objects. PHP 5 only.
  298. case T_PUBLIC: // public classes and objects. PHP 5 only.
  299. // captures the class visibilty
  300. is_null($this->inClass) or $this->id['access'] = array($id, $value);
  301. break;
  302. case T_STATIC: // static variable scope
  303. if (!is_null($this->inClass) and is_null($inFunct)) {
  304. // captures the static property within a class and
  305. // outside of a function
  306. $this->id[$type] = $id;
  307. }
  308. break;
  309. case T_VAR: // var classes and objects
  310. // captures the class property
  311. is_null($this->inClass) or $this->id[$type] = $id;
  312. break;
  313. case T_STRING:
  314. // sets define DocBlock
  315. $value == 'define' and $this->block->setDefine($id);
  316. break;
  317. case T_VARIABLE: // $foo variables
  318. if (isset($this->id[T_INCLUDE])) {
  319. // including a variable instead of a string, sets the include DocBlock
  320. $this->block->build($this->id[T_INCLUDE]);
  321. } else if (isset($this->id[T_GLOBAL])) {
  322. // a global variable, sets the global DocBlock, e.g. global $var
  323. $this->block->setGlobal($this->id[T_GLOBAL], $token, $allTokens);
  324. } else if (is_null($this->inClass) and is_null($inFunct) and $value == '$GLOBALS') {
  325. // a GLOBALS variable outside of a class and function
  326. // sets the global variable DocBlock, e.g. $GLOBALS['foo']
  327. $this->block->setGLOBALS($id, $allTokens);
  328. } else if (isset($this->id['access']) or
  329. isset($this->id[T_VAR])or isset($this->id[T_STATIC])) {
  330. // a class property, sets the class variable
  331. $this->block->setVar($token);
  332. }
  333. break;
  334. }
  335. }
  336. if (!$isPageBlock) {
  337. // no Page-level DocBlock, determines the PHP version, sets the Page-level DocBlock
  338. $info = $this->info->parseString($data);
  339. list($this->phpVersion) = explode('.', $info['version']);
  340. $this->block->setPage($openTagID);
  341. }
  342. // re-assembles all the tokens
  343. $result = $this->putAll();
  344. }
  345. return $result;
  346. }
  347. /**
  348. * Re-assembles the source code tokens into a string
  349. *
  350. * @return boolean true on success, false on failure
  351. * @access private
  352. */
  353. private function putAll()
  354. {
  355. // creates the array_reduce callback, reduces the array to a string made of token values
  356. $callback = create_function('$string, $token', 'return $string .= $token[\'value\'];');
  357. return array_reduce($this->tokens, $callback);
  358. }
  359. /**
  360. * Sets the token value
  361. *
  362. * @param integer $id the token identification number
  363. * @param string $value the token value
  364. * @return boolean true if the token is valid, false otherwise
  365. * @access public
  366. */
  367. public function set($id, $value)
  368. {
  369. $isValid = $this->isValid($id) and $this->tokens[$id]['value'] = $value;
  370. return $isValid;
  371. }
  372. /**
  373. * Slices a subset of tokens
  374. *
  375. * @param integer $offset the token identification number to start looking at
  376. * @param string $openBracket the delimiter to start slicing at
  377. * @param mixed $closeBracket the delimiter to stop slicing at
  378. * @param integer $bracketCount to set to 1 if the offset is past the first delimiter
  379. * @return array the sliced tokens
  380. * @access private
  381. */
  382. public function slice($offset = 0, $openBracket = null, $closeBracket = null, $bracketCount = null)
  383. {
  384. $tokens = array();
  385. foreach($this->phpTokens as $token) {
  386. if ($token['id'] >= $offset) {
  387. // processes tokens after the offset
  388. $tokens[] = $token; // captures the token
  389. if ($openBracket !== null) {
  390. // only captures tokens delimited by the brackets
  391. // captures all types of open curly braces
  392. $openBracket == '{' and
  393. in_array($token['type'], array(T_CURLY_OPEN, T_DOLLAR_OPEN_CURLY_BRACES)) and
  394. $token['type'] = '{';
  395. // counts enclosed opening and closing brackets
  396. $token['type'] == $openBracket and $bracketCount++ or
  397. $token['type'] == $closeBracket and $bracketCount--;
  398. if ($bracketCount === 0) {
  399. // reached the last closing bracket
  400. break;
  401. }
  402. }
  403. }
  404. }
  405. return $tokens;
  406. }
  407. /**
  408. * Tidies a token
  409. *
  410. * An array_walk() callback function.
  411. *
  412. * @param array &$token the token
  413. * @param integer $id the token identification number
  414. * @return void
  415. * @access private
  416. * @see self::getAll()
  417. */
  418. private function tidy(&$token, $id)
  419. {
  420. if (is_array($token)) {
  421. // a PHP token
  422. // extracts the token type, e.g. T_CONSTANT_ENCAPSED_STRING
  423. $tidied['type'] = current($token);
  424. $tidied['type'] == T_PAAMAYIM_NEKUDOTAYIM and $tidied['type'] = T_DOUBLE_COLON;
  425. // extracts the token value, e.g. "foo"
  426. $tidied['value'] = next($token);
  427. // captures the token type as a string, note: only useful for debugging purposes
  428. $tidied['name'] = token_name($tidied['type']);
  429. } else {
  430. // a single character, e.g. ";"
  431. $tidied['type'] = $tidied['value'] = $token;
  432. }
  433. // captures the token position
  434. $tidied['id'] = $id;
  435. $token = $tidied;
  436. }
  437. }
  438. ?>