PHPCodeAnalyzer
[ class tree: PHPCodeAnalyzer ] [ index: PHPCodeAnalyzer ] [ all elements ]

Source for file PHPCodeAnalyzer.php

Documentation is available at PHPCodeAnalyzer.php

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

Documentation generated on Sun, 12 Dec 2004 17:15:31 -0600 by phpDocumentor 1.3.0RC3