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;
127 var $_previousToken = null;
131 * parse source filling informational arrays
135 $tokens = token_get_all($this->source
);
137 // mapping of token to method to call
139 T_STRING
=> 'handleString',
140 T_CONSTANT_ENCAPSED_STRING
=> 'handleString',
141 T_ENCAPSED_AND_WHITESPACE
=> 'handleString',
142 T_CHARACTER
=> 'handleString',
143 T_NUM_STRING
=> 'handleString',
144 T_DNUMBER
=> 'handleString',
145 T_FUNC_C
=> 'handleString',
146 T_CLASS_C
=> 'handleString',
147 T_FILE
=> 'handleString',
148 T_LINE
=> 'handleString',
149 T_DOUBLE_ARROW
=> 'handleString',
151 T_ARRAY
=> 'handleClearStrings',
152 T_CONCAT_EQUAL
=> 'handleClearStrings',
154 T_DOUBLE_COLON
=> 'handleDoubleColon',
155 T_NEW
=> 'handleNew',
156 T_OBJECT_OPERATOR
=> 'handleObjectOperator',
157 T_VARIABLE
=> 'handleVariable',
158 T_FUNCTION
=> 'handleFunction',
159 T_OLD_FUNCTION
=> 'handleFunction',
160 T_CLASS
=> 'handleClass',
161 T_WHITESPACE
=> 'handleWhitespace',
162 T_INLINE_HTML
=> 'handleWhitespace',
163 T_OPEN_TAG
=> 'handleWhitespace',
164 T_CLOSE_TAG
=> 'handleWhitespace',
168 T_ECHO
=> 'handleConstruct',
169 T_EVAL
=> 'handleConstruct',
170 T_UNSET
=> 'handleConstruct',
171 T_ISSET
=> 'handleConstruct',
172 T_PRINT
=> 'handleConstruct',
173 T_FOR
=> 'handleConstruct',
174 T_FOREACH
=> 'handleConstruct',
175 T_EMPTY
=> 'handleConstruct',
176 T_EXIT
=> 'handleConstruct',
177 T_CASE
=> 'handleConstruct',
178 T_GLOBAL
=> 'handleConstruct',
179 T_UNSET
=> 'handleConstruct',
180 T_WHILE
=> 'handleConstruct',
181 T_DO
=> 'handleConstruct',
182 T_IF
=> 'handleConstruct',
183 T_LIST
=> 'handleConstruct',
184 T_RETURN
=> 'handleConstruct',
185 T_STATIC
=> 'handleConstruct',
186 T_ENDFOR
=> 'handleConstruct',
187 T_ENDFOREACH
=> 'handleConstruct',
188 T_ENDIF
=> 'handleConstruct',
189 T_ENDSWITCH
=> 'handleConstruct',
190 T_ENDWHILE
=> 'handleConstruct',
192 T_INCLUDE
=> 'handleInclude',
193 T_INCLUDE_ONCE
=> 'handleInclude',
194 T_REQUIRE
=> 'handleInclude',
195 T_REQUIRE_ONCE
=> 'handleInclude',
198 foreach($tokens as $token)
200 if (is_string($token))
202 // we have a simple 1-character token
203 $this->handleSimpleToken($token);
207 list($id, $text) = $token;
208 if (isset($handleMap[$id]))
210 $call = $handleMap[$id];
211 $this->$call($id,$text);
215 echo token_name($id).": $text<br>\n";
222 * Handle a 1 char token
225 function handleSimpleToken($token)
229 $this->currentStrings
.= $token;
235 if ($this->staticClass
!== false)
237 if (!isset($this->calledStaticMethods
[$this->staticClass
][$this->currentString
]))
239 $this->calledStaticMethods
[$this->staticClass
][$this->currentString
]
242 $this->calledStaticMethods
[$this->staticClass
][$this->currentString
][]
244 $this->staticClass
= false;
246 else if ($this->currentVar
!== false)
248 if (!isset($this->calledMethods
[$this->currentVar
][$this->currentString
]))
250 $this->calledMethods
[$this->currentVar
][$this->currentString
] = array();
252 $this->calledMethods
[$this->currentVar
][$this->currentString
][] = $this->lineNumber
;
253 $this->currentVar
= false;
255 else if ($this->inNew
!== false)
257 $this->classInstantiated();
259 else if ($this->currentString
!== null)
261 $this->functionCalled();
263 //$this->currentString = null;
269 if ($this->inNew
!== false)
271 $this->classInstantiated();
273 else if ($this->inInclude
!== false)
275 $this->fileIncluded();
277 else if ($this->currentVar
!== false)
279 $this->useMemberVar();
281 $this->currentString
= null;
282 $this->currentStrings
= null;
286 $this->useMemberVar(false);
289 if($this->_previousToken
== ')'){
290 $this->currentVar
= false;
291 $this->currentString
= null;
295 $this->_previousToken
= $token;
299 * handle includes and requires
302 function handleInclude($id,$text)
304 $this->inInclude
= true;
305 $this->handleConstruct($id,$text);
309 * handle String tokens
312 function handleString($id,$text)
314 $this->currentString
= $text;
315 $this->currentStrings
.= $text;
319 * handle String tokens
322 function handleClearStrings($id,$text)
324 $this->currentString
= '';
331 function handleVariable($id,$text)
333 $this->currentString
= $text;
334 $this->currentStrings
.= $text;
335 $this->useVariable();
340 * handle Double Colon tokens
343 function handleDoubleColon($id,$text)
345 $this->staticClass
= $this->currentString
;
346 $this->currentString
= null;
353 function handleNew($id,$text)
362 function handleFunction($id,$text)
364 $this->createdFunctions
[] = $this->lineNumber
;
371 function handleClass($id,$text)
373 $this->createdClasses
[] = $this->lineNumber
;
380 function handleObjectOperator($id,$text)
382 $this->currentVar
= $this->currentString
;
383 $this->currentString
= null;
384 $this->currentStrings
.= $text;
388 * handle whitespace to figure out line counts
391 function handleWhitespace($id,$text)
393 $this->lineNumber+
=substr_count($text,"\n");
394 if ($id == T_CLOSE_TAG
)
396 $this->handleSimpleToken(";");
402 * as has been used we must have a var before it
406 function handleAs($id,$text)
408 $this->handleSimpleToken(";");
412 * a language construct has been called record it
415 function handleConstruct($id,$construct)
417 if (!isset($this->calledConstructs
[$construct]))
419 $this->calledConstructs
[$construct] = array();
421 $this->calledConstructs
[$construct][] = $this->lineNumber
;
422 $this->currentString
= null;
426 * a class was Instantiated record it
429 function classInstantiated()
431 if (!isset($this->classesInstantiated
[$this->currentString
]))
433 $this->classesInstantiated
[$this->currentString
] = array();
435 $this->classesInstantiated
[$this->currentString
][] = $this->lineNumber
;
436 $this->inNew
= false;
440 * a file was included record it
443 function fileIncluded()
445 if (!isset($this->filesIncluded
[$this->currentStrings
]))
447 $this->filesIncluded
[$this->currentStrings
] = array();
449 $this->filesIncluded
[$this->currentStrings
][] = $this->lineNumber
;
450 $this->inInclude
= false;
451 $this->currentString
= null;
452 $this->currentStrings
= "";
456 * a function was called record it
459 function functionCalled($id = false)
461 $function_name = trim(rtrim($this->currentStrings
,'('));
462 if(empty($this->currentStrings
) ||
substr($function_name,-1) != ']'){
463 $function_name = $this->currentString
;
464 if(strstr('"\'',substr($function_name,-1))){
465 $this->currentString
= null;
470 if (!isset($this->calledFunctions
[$function_name]))
472 $this->calledFunctions
[$function_name] = array();
475 $this->calledFunctions
[$function_name][] = $this->lineNumber
;
476 $this->currentString
= null;
480 * we used a member variable record it
483 function useMemberVar($reset = true)
485 if (!isset($this->usedMemberVariables
[$this->currentVar
][$this->currentString
])){
486 $this->usedMemberVariables
[$this->currentVar
][$this->currentString
] = array();
488 $this->usedMemberVariables
[$this->currentVar
][$this->currentString
][] = $this->lineNumber
;
490 $this->currentVar
= false;
491 $this->currentString
= null;
496 * we used a variable record it
499 function useVariable()
501 if (!isset($this->usedVariables
[$this->currentString
]))
503 $this->usedVariables
[$this->currentString
] = array();
505 $this->usedVariables
[$this->currentString
][] = $this->lineNumber
;