PageRenderTime 67ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/include/Savant/Savant2/PHPCodeAnalyzer.php

https://github.com/radicaldesigns/amp
PHP | 471 lines | 267 code | 39 blank | 165 comment | 28 complexity | 2768737ef9d363a0f7ab75059ffaf0a6 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, BSD-3-Clause, LGPL-2.0, CC-BY-SA-3.0, AGPL-1.0
  1. <?php
  2. /**
  3. * A class for performing code analysis for php scripts
  4. * It is designed to be the heart of a code limiting script
  5. * to use with Savant {@link http://phpsavant.com}
  6. *
  7. * This code should be php4 compatiable but i've only run it in php5 and some of the Tokenizer constants have changed
  8. *
  9. * @author Joshua Eichorn <josh@bluga.net>
  10. * @copyright Joshua Eichorn 2004
  11. * @package PHPCodeAnalyzer
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU Lesser General Public License as
  15. * published by the Free Software Foundation; either version 2.1 of the
  16. * License, or (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful, but
  19. * WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  21. * Lesser General Public License for more details.
  22. *
  23. * @license http://www.gnu.org/copyleft/lesser.html LGPL
  24. */
  25. /**#@+
  26. * compat tokeniezer defines
  27. */
  28. if (! defined('T_OLD_FUNCTION')) {
  29. define('T_OLD_FUNCTION', T_FUNCTION);
  30. }
  31. if (!defined('T_ML_COMMENT')) {
  32. define('T_ML_COMMENT', T_COMMENT);
  33. } else {
  34. define('T_DOC_COMMENT', T_ML_COMMENT);
  35. }
  36. /**#@-*/
  37. /**
  38. * Code Analysis class
  39. *
  40. * Example Usage:
  41. * <code>
  42. * $analyzer = new PHPCodeAnalyzer();
  43. * $analyzer->source = file_get_contents(__FILE__);
  44. * $analyzer->analyze();
  45. * print_r($analyzer->calledMethods);
  46. * </code>
  47. *
  48. * @todo is it important to grab the details from creating new functions defines classes?
  49. * @todo support php5 only stuff like interface
  50. *
  51. * @version 0.4
  52. * @license http://www.gnu.org/copyleft/lesser.html LGPL
  53. * @copyright Joshua Eichorn 2004
  54. * @package PHPCodeAnalyzer
  55. * @author Joshua Eichorn <josh@bluga.net>
  56. */
  57. class PHPCodeAnalyzer
  58. {
  59. /**
  60. * Source code to analyze
  61. */
  62. var $source = "";
  63. /**
  64. * functions called
  65. */
  66. var $calledFunctions = array();
  67. /**
  68. * Called constructs
  69. */
  70. var $calledConstructs = array();
  71. /**
  72. * methods called
  73. */
  74. var $calledMethods = array();
  75. /**
  76. * static methods called
  77. */
  78. var $calledStaticMethods = array();
  79. /**
  80. * new classes instantiated
  81. */
  82. var $classesInstantiated = array();
  83. /**
  84. * variables used
  85. */
  86. var $usedVariables = array();
  87. /**
  88. * member variables used
  89. */
  90. var $usedMemberVariables = array();
  91. /**
  92. * classes created
  93. */
  94. var $createdClasses = array();
  95. /**
  96. * functions created
  97. */
  98. var $createdFunctions = array();
  99. /**
  100. * Files includes or requried
  101. */
  102. var $filesIncluded = array();
  103. // private variables
  104. /**#@+
  105. * @access private
  106. */
  107. var $currentString = null;
  108. var $currentStrings = null;
  109. var $currentVar = false;
  110. var $staticClass = false;
  111. var $inNew = false;
  112. var $inInclude = false;
  113. var $lineNumber = 1;
  114. /**#@-*/
  115. /**
  116. * parse source filling informational arrays
  117. */
  118. function analyze()
  119. {
  120. $tokens = token_get_all($this->source);
  121. // mapping of token to method to call
  122. $handleMap = array(
  123. T_STRING => 'handleString',
  124. T_CONSTANT_ENCAPSED_STRING => 'handleString',
  125. T_ENCAPSED_AND_WHITESPACE => 'handleString',
  126. T_CHARACTER => 'handleString',
  127. T_NUM_STRING => 'handleString',
  128. T_DNUMBER => 'handleString',
  129. T_FUNC_C => 'handleString',
  130. T_CLASS_C => 'handleString',
  131. T_FILE => 'handleString',
  132. T_LINE => 'handleString',
  133. T_DOUBLE_ARROW => 'handleString',
  134. T_DOUBLE_COLON => 'handleDoubleColon',
  135. T_NEW => 'handleNew',
  136. T_OBJECT_OPERATOR => 'handleObjectOperator',
  137. T_VARIABLE => 'handleVariable',
  138. T_FUNCTION => 'handleFunction',
  139. T_OLD_FUNCTION => 'handleFunction',
  140. T_CLASS => 'handleClass',
  141. T_WHITESPACE => 'handleWhitespace',
  142. T_INLINE_HTML => 'handleWhitespace',
  143. T_OPEN_TAG => 'handleWhitespace',
  144. T_CLOSE_TAG => 'handleWhitespace',
  145. T_AS => 'handleAs',
  146. T_ECHO => 'handleConstruct',
  147. T_EVAL => 'handleConstruct',
  148. T_UNSET => 'handleConstruct',
  149. T_ISSET => 'handleConstruct',
  150. T_PRINT => 'handleConstruct',
  151. T_FOR => 'handleConstruct',
  152. T_FOREACH=> 'handleConstruct',
  153. T_EMPTY => 'handleConstruct',
  154. T_EXIT => 'handleConstruct',
  155. T_CASE => 'handleConstruct',
  156. T_GLOBAL=> 'handleConstruct',
  157. T_UNSET => 'handleConstruct',
  158. T_WHILE => 'handleConstruct',
  159. T_DO => 'handleConstruct',
  160. T_IF => 'handleConstruct',
  161. T_LIST => 'handleConstruct',
  162. T_RETURN=> 'handleConstruct',
  163. T_STATIC=> 'handleConstruct',
  164. T_ENDFOR=> 'handleConstruct',
  165. T_ENDFOREACH=> 'handleConstruct',
  166. T_ENDIF=> 'handleConstruct',
  167. T_ENDSWITCH=> 'handleConstruct',
  168. T_ENDWHILE=> 'handleConstruct',
  169. T_INCLUDE => 'handleInclude',
  170. T_INCLUDE_ONCE => 'handleInclude',
  171. T_REQUIRE => 'handleInclude',
  172. T_REQUIRE_ONCE => 'handleInclude',
  173. );
  174. foreach($tokens as $token)
  175. {
  176. if (is_string($token))
  177. {
  178. // we have a simple 1-character token
  179. $this->handleSimpleToken($token);
  180. }
  181. else
  182. {
  183. list($id, $text) = $token;
  184. if (isseT($handleMap[$id]))
  185. {
  186. $call = $handleMap[$id];
  187. $this->$call($id,$text);
  188. }
  189. /*else
  190. {
  191. echo token_name($id).": $text<br>\n";
  192. }*/
  193. }
  194. }
  195. }
  196. /**
  197. * Handle a 1 char token
  198. * @access private
  199. */
  200. function handleSimpleToken($token)
  201. {
  202. if ($token !== ";")
  203. {
  204. $this->currentStrings .= $token;
  205. }
  206. switch($token)
  207. {
  208. case "(":
  209. // method is called
  210. if ($this->staticClass !== false)
  211. {
  212. if (!isset($this->calledStaticMethods[$this->staticClass][$this->currentString]))
  213. {
  214. $this->calledStaticMethods[$this->staticClass][$this->currentString]
  215. = array();
  216. }
  217. $this->calledStaticMethods[$this->staticClass][$this->currentString][]
  218. = $this->lineNumber;
  219. $this->staticClass = false;
  220. }
  221. else if ($this->currentVar !== false)
  222. {
  223. if (!isset($this->calledMethods[$this->currentVar][$this->currentString]))
  224. {
  225. $this->calledMethods[$this->currentVar][$this->currentString] = array();
  226. }
  227. $this->calledMethods[$this->currentVar][$this->currentString][] = $this->lineNumber;
  228. $this->currentVar = false;
  229. }
  230. else if ($this->inNew !== false)
  231. {
  232. $this->classInstantiated();
  233. }
  234. else if ($this->currentString !== null)
  235. {
  236. $this->functionCalled();
  237. }
  238. //$this->currentString = null;
  239. break;
  240. case "=":
  241. case ";":
  242. if ($this->inNew !== false)
  243. {
  244. $this->classInstantiated();
  245. }
  246. else if ($this->inInclude !== false)
  247. {
  248. $this->fileIncluded();
  249. }
  250. else if ($this->currentVar !== false)
  251. {
  252. $this->useMemberVar();
  253. }
  254. $this->currentString = null;
  255. $this->currentStrings = null;
  256. break;
  257. }
  258. }
  259. /**
  260. * handle includes and requires
  261. * @access private
  262. */
  263. function handleInclude($id,$text)
  264. {
  265. $this->inInclude = true;
  266. $this->handleConstruct($id,$text);
  267. }
  268. /**
  269. * handle String tokens
  270. * @access private
  271. */
  272. function handleString($id,$text)
  273. {
  274. $this->currentString = $text;
  275. $this->currentStrings .= $text;
  276. }
  277. /**
  278. * handle variables
  279. * @access private
  280. */
  281. function handleVariable($id,$text)
  282. {
  283. $this->currentString = $text;
  284. $this->currentStrings .= $text;
  285. $this->useVariable();
  286. }
  287. /**
  288. * handle Double Colon tokens
  289. * @access private
  290. */
  291. function handleDoubleColon($id,$text)
  292. {
  293. $this->staticClass = $this->currentString;
  294. $this->currentString = null;
  295. }
  296. /**
  297. * handle new keyword
  298. * @access private
  299. */
  300. function handleNew($id,$text)
  301. {
  302. $this->inNew = true;
  303. }
  304. /**
  305. * handle function
  306. * @access private
  307. */
  308. function handleFunction($id,$text)
  309. {
  310. $this->createdFunctions[] = $this->lineNumber;
  311. }
  312. /**
  313. * handle class
  314. * @access private
  315. */
  316. function handleClass($id,$text)
  317. {
  318. $this->createdClasses[] = $this->lineNumber;
  319. }
  320. /**
  321. * Handle ->
  322. * @access private
  323. */
  324. function handleObjectOperator($id,$text)
  325. {
  326. $this->currentVar = $this->currentString;
  327. $this->currentString = null;
  328. $this->currentStrings .= $text;
  329. }
  330. /**
  331. * handle whitespace to figure out line counts
  332. * @access private
  333. */
  334. function handleWhitespace($id,$text)
  335. {
  336. $this->lineNumber+=substr_count($text,"\n");
  337. if ($id == T_CLOSE_TAG)
  338. {
  339. $this->handleSimpleToken(";");
  340. }
  341. }
  342. /**
  343. * as has been used we must have a var before it
  344. *
  345. * @access private
  346. */
  347. function handleAs($id,$text)
  348. {
  349. $this->handleSimpleToken(";");
  350. }
  351. /**
  352. * a language construct has been called record it
  353. * @access private
  354. */
  355. function handleConstruct($id,$construct)
  356. {
  357. if (!isset($this->calledConstructs[$construct]))
  358. {
  359. $this->calledConstructs[$construct] = array();
  360. }
  361. $this->calledConstructs[$construct][] = $this->lineNumber;
  362. $this->currentString = null;
  363. }
  364. /**
  365. * a class was Instantiated record it
  366. * @access private
  367. */
  368. function classInstantiated()
  369. {
  370. if (!isset($this->classesInstantiated[$this->currentString]))
  371. {
  372. $this->classesInstantiated[$this->currentString] = array();
  373. }
  374. $this->classesInstantiated[$this->currentString][] = $this->lineNumber;
  375. $this->inNew = false;
  376. }
  377. /**
  378. * a file was included record it
  379. * @access private
  380. */
  381. function fileIncluded()
  382. {
  383. if (!isset($this->filesIncluded[$this->currentStrings]))
  384. {
  385. $this->filesIncluded[$this->currentStrings] = array();
  386. }
  387. $this->filesIncluded[$this->currentStrings][] = $this->lineNumber;
  388. $this->inInclude = false;
  389. $this->currentString = null;
  390. $this->currentStrings = "";
  391. }
  392. /**
  393. * a function was called record it
  394. * @access private
  395. */
  396. function functionCalled($id = false)
  397. {
  398. if (!isset($this->calledFunctions[$this->currentString]))
  399. {
  400. $this->calledFunctions[$this->currentString] = array();
  401. }
  402. $this->calledFunctions[$this->currentString][] = $this->lineNumber;
  403. $this->currentString = null;
  404. }
  405. /**
  406. * we used a member variable record it
  407. * @access private
  408. */
  409. function useMemberVar()
  410. {
  411. if (!isset($this->usedMemberVariables[$this->currentVar][$this->currentString]))
  412. {
  413. $this->usedMemberVariables[$this->currentVar][$this->currentString] = array();
  414. }
  415. $this->usedMemberVariables[$this->currentVar][$this->currentString][] = $this->lineNumber;
  416. $this->currentVar = false;
  417. $this->currentString = null;
  418. }
  419. /**
  420. * we used a variable record it
  421. * @access private
  422. */
  423. function useVariable()
  424. {
  425. if (!isset($this->usedVariables[$this->currentString]))
  426. {
  427. $this->usedVariables[$this->currentString] = array();
  428. }
  429. $this->usedVariables[$this->currentString][] = $this->lineNumber;
  430. }
  431. }
  432. ?>