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}
7 * This code should be php4 compatiable but i've only run it in php5 and some of the Tokenizer constants have changed
9 * @author Joshua Eichorn <josh@bluga.net>
10 * @copyright Joshua Eichorn 2004
11 * @package PHPCodeAnalyzer
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.
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.
23 * @license http://www.gnu.org/copyleft/lesser.html LGPL
27 * compat tokeniezer defines
29 if (! defined('T_OLD_FUNCTION')) {
30 define('T_OLD_FUNCTION', T_FUNCTION
);
32 if (!defined('T_ML_COMMENT')) {
33 define('T_ML_COMMENT', T_COMMENT
);
35 define('T_DOC_COMMENT', T_ML_COMMENT
);
44 * $analyzer = new PHPCodeAnalyzer();
45 * $analyzer->source = file_get_contents(__FILE__);
46 * $analyzer->analyze();
47 * print_r($analyzer->calledMethods);
50 * @todo is it important to grab the details from creating new functions defines classes?
51 * @todo support php5 only stuff like interface
54 * @license http://www.gnu.org/copyleft/lesser.html LGPL
55 * @copyright Joshua Eichorn 2004
56 * @package PHPCodeAnalyzer
57 * @author Joshua Eichorn <josh@bluga.net>
62 * Source code to analyze
69 var $calledFunctions = array();
74 var $calledConstructs = array();
79 var $calledMethods = array();
82 * static methods called
84 var $calledStaticMethods = array();
87 * new classes instantiated
89 var $classesInstantiated = array();
94 var $usedVariables = array();
97 * member variables used
99 var $usedMemberVariables = array();
104 var $createdClasses = array();
109 var $createdFunctions = array();
112 * Files includes or requried
114 var $filesIncluded = array();
120 var $currentString = null;
121 var $currentStrings = null;
122 var $currentVar = false;
123 var $staticClass = false;
125 var $inInclude = false;
130 * parse source filling informational arrays
134 $tokens = token_get_all($this->source
);
136 // mapping of token to method to call
138 T_STRING
=> 'handleString',
139 T_CONSTANT_ENCAPSED_STRING
=> 'handleString',
140 T_ENCAPSED_AND_WHITESPACE
=> 'handleString',
141 T_CHARACTER
=> 'handleString',
142 T_NUM_STRING
=> 'handleString',
143 T_DNUMBER
=> 'handleString',
144 T_FUNC_C
=> 'handleString',
145 T_CLASS_C
=> 'handleString',
146 T_FILE
=> 'handleString',
147 T_LINE
=> 'handleString',
148 T_DOUBLE_ARROW
=> 'handleString',
150 T_ARRAY
=> 'handleClearStrings',
151 T_CONCAT_EQUAL
=> 'handleClearStrings',
153 T_DOUBLE_COLON
=> 'handleDoubleColon',
154 T_NEW
=> 'handleNew',
155 T_OBJECT_OPERATOR
=> 'handleObjectOperator',
156 T_VARIABLE
=> 'handleVariable',
157 T_FUNCTION
=> 'handleFunction',
158 T_OLD_FUNCTION
=> 'handleFunction',
159 T_CLASS
=> 'handleClass',
160 T_WHITESPACE
=> 'handleWhitespace',
161 T_INLINE_HTML
=> 'handleWhitespace',
162 T_OPEN_TAG
=> 'handleWhitespace',
163 T_CLOSE_TAG
=> 'handleWhitespace',
167 T_ECHO
=> 'handleConstruct',
168 T_EVAL
=> 'handleConstruct',
169 T_UNSET
=> 'handleConstruct',
170 T_ISSET
=> 'handleConstruct',
171 T_PRINT
=> 'handleConstruct',
172 T_FOR
=> 'handleConstruct',
173 T_FOREACH
=> 'handleConstruct',
174 T_EMPTY
=> 'handleConstruct',
175 T_EXIT
=> 'handleConstruct',
176 T_CASE
=> 'handleConstruct',
177 T_GLOBAL
=> 'handleConstruct',
178 T_UNSET
=> 'handleConstruct',
179 T_WHILE
=> 'handleConstruct',
180 T_DO
=> 'handleConstruct',
181 T_IF
=> 'handleConstruct',
182 T_LIST
=> 'handleConstruct',
183 T_RETURN
=> 'handleConstruct',
184 T_STATIC
=> 'handleConstruct',
185 T_ENDFOR
=> 'handleConstruct',
186 T_ENDFOREACH
=> 'handleConstruct',
187 T_ENDIF
=> 'handleConstruct',
188 T_ENDSWITCH
=> 'handleConstruct',
189 T_ENDWHILE
=> 'handleConstruct',
191 T_INCLUDE
=> 'handleInclude',
192 T_INCLUDE_ONCE
=> 'handleInclude',
193 T_REQUIRE
=> 'handleInclude',
194 T_REQUIRE_ONCE
=> 'handleInclude',
197 foreach($tokens as $token)
199 if (is_string($token))
201 // we have a simple 1-character token
202 $this->handleSimpleToken($token);
206 list($id, $text) = $token;
207 if (isset($handleMap[$id]))
209 $call = $handleMap[$id];
210 $this->$call($id,$text);
214 echo token_name($id).": $text<br>\n";
221 * Handle a 1 char token
224 function handleSimpleToken($token)
228 $this->currentStrings
.= $token;
234 if ($this->staticClass
!== false)
236 if (!isset($this->calledStaticMethods
[$this->staticClass
][$this->currentString
]))
238 $this->calledStaticMethods
[$this->staticClass
][$this->currentString
]
241 $this->calledStaticMethods
[$this->staticClass
][$this->currentString
][]
243 $this->staticClass
= false;
245 else if ($this->currentVar
!== false)
247 if (!isset($this->calledMethods
[$this->currentVar
][$this->currentString
]))
249 $this->calledMethods
[$this->currentVar
][$this->currentString
] = array();
251 $this->calledMethods
[$this->currentVar
][$this->currentString
][] = $this->lineNumber
;
252 $this->currentVar
= false;
254 else if ($this->inNew
!== false)
256 $this->classInstantiated();
258 else if ($this->currentString
!== null)
260 $this->functionCalled();
262 //$this->currentString = null;
266 if ($this->inNew
!== false)
268 $this->classInstantiated();
270 else if ($this->inInclude
!== false)
272 $this->fileIncluded();
274 else if ($this->currentVar
!== false)
276 $this->useMemberVar();
278 $this->currentString
= null;
279 $this->currentStrings
= null;
283 $this->useMemberVar(false);
289 * handle includes and requires
292 function handleInclude($id,$text)
294 $this->inInclude
= true;
295 $this->handleConstruct($id,$text);
299 * handle String tokens
302 function handleString($id,$text)
304 $this->currentString
= $text;
305 $this->currentStrings
.= $text;
309 * handle String tokens
312 function handleClearStrings($id,$text)
314 $this->currentString
= '';
321 function handleVariable($id,$text)
323 $this->currentString
= $text;
324 $this->currentStrings
.= $text;
325 $this->useVariable();
330 * handle Double Colon tokens
333 function handleDoubleColon($id,$text)
335 $this->staticClass
= $this->currentString
;
336 $this->currentString
= null;
343 function handleNew($id,$text)
352 function handleFunction($id,$text)
354 $this->createdFunctions
[] = $this->lineNumber
;
361 function handleClass($id,$text)
363 $this->createdClasses
[] = $this->lineNumber
;
370 function handleObjectOperator($id,$text)
372 $this->currentVar
= $this->currentString
;
373 $this->currentString
= null;
374 $this->currentStrings
.= $text;
378 * handle whitespace to figure out line counts
381 function handleWhitespace($id,$text)
383 $this->lineNumber+
=substr_count($text,"\n");
384 if ($id == T_CLOSE_TAG
)
386 $this->handleSimpleToken(";");
392 * as has been used we must have a var before it
396 function handleAs($id,$text)
398 $this->handleSimpleToken(";");
402 * a language construct has been called record it
405 function handleConstruct($id,$construct)
407 if (!isset($this->calledConstructs
[$construct]))
409 $this->calledConstructs
[$construct] = array();
411 $this->calledConstructs
[$construct][] = $this->lineNumber
;
412 $this->currentString
= null;
416 * a class was Instantiated record it
419 function classInstantiated()
421 if (!isset($this->classesInstantiated
[$this->currentString
]))
423 $this->classesInstantiated
[$this->currentString
] = array();
425 $this->classesInstantiated
[$this->currentString
][] = $this->lineNumber
;
426 $this->inNew
= false;
430 * a file was included record it
433 function fileIncluded()
435 if (!isset($this->filesIncluded
[$this->currentStrings
]))
437 $this->filesIncluded
[$this->currentStrings
] = array();
439 $this->filesIncluded
[$this->currentStrings
][] = $this->lineNumber
;
440 $this->inInclude
= false;
441 $this->currentString
= null;
442 $this->currentStrings
= "";
446 * a function was called record it
449 function functionCalled($id = false)
451 $function_name = trim(rtrim($this->currentStrings
,'('));
452 if(empty($this->currentStrings
) ||
substr($function_name,-1) != ']'){
453 $function_name = $this->currentString
;
454 if(strstr('"\'',substr($function_name,-1))){
455 $this->currentString
= null;
460 if (!isset($this->calledFunctions
[$function_name]))
462 $this->calledFunctions
[$function_name] = array();
465 $this->calledFunctions
[$function_name][] = $this->lineNumber
;
466 $this->currentString
= null;
470 * we used a member variable record it
473 function useMemberVar($reset = true)
475 if (!isset($this->usedMemberVariables
[$this->currentVar
][$this->currentString
])){
476 $this->usedMemberVariables
[$this->currentVar
][$this->currentString
] = array();
478 $this->usedMemberVariables
[$this->currentVar
][$this->currentString
][] = $this->lineNumber
;
480 $this->currentVar
= false;
481 $this->currentString
= null;
486 * we used a variable record it
489 function useVariable()
491 if (!isset($this->usedVariables
[$this->currentString
]))
493 $this->usedVariables
[$this->currentString
] = array();
495 $this->usedVariables
[$this->currentString
][] = $this->lineNumber
;