Stacey Richards Stacey Richards - 4 months ago 15
PHP Question

How can I find unused functions in a PHP project

How can I find unused functions in a PHP project?

Are there features or API's built into PHP that will allow me to analyse my codebase - for example Reflection,

?

Are these API's feature rich enough for me not to have to rely on a third party tool to perform this type of analysis?

Answer

Thanks Greg and Dave for the feedback. Wasn't quite what I was looking for, but I decided to put a bit of time into researching it and came up with this quick and dirty solution:

<?php
    $functions = array();
    $path = "/path/to/my/php/project";
    define_dir($path, $functions);
    reference_dir($path, $functions);
    echo
    	"<table>" .
    		"<tr>" .
    			"<th>Name</th>" .
    			"<th>Defined</th>" .
    			"<th>Referenced</th>" .
    		"</tr>";
    foreach ($functions as $name => $value) {
    	echo
    		"<tr>" . 
    			"<td>" . htmlentities($name) . "</td>" .
    			"<td>" . (isset($value[0]) ? count($value[0]) : "-") . "</td>" .
    			"<td>" . (isset($value[1]) ? count($value[1]) : "-") . "</td>" .
    		"</tr>";
    }
    echo "</table>";
    function define_dir($path, &$functions) {
    	if ($dir = opendir($path)) {
    		while (($file = readdir($dir)) !== false) {
    			if (substr($file, 0, 1) == ".") continue;
    			if (is_dir($path . "/" . $file)) {
    				define_dir($path . "/" . $file, $functions);
    			} else {
    				if (substr($file, - 4, 4) != ".php") continue;
    				define_file($path . "/" . $file, $functions);
    			}
    		}
    	}		
    }
    function define_file($path, &$functions) {
    	$tokens = token_get_all(file_get_contents($path));
    	for ($i = 0; $i < count($tokens); $i++) {
    		$token = $tokens[$i];
    		if (is_array($token)) {
    			if ($token[0] != T_FUNCTION) continue;
    			$i++;
    			$token = $tokens[$i];
    			if ($token[0] != T_WHITESPACE) die("T_WHITESPACE");
    			$i++;
    			$token = $tokens[$i];
    			if ($token[0] != T_STRING) die("T_STRING");
    			$functions[$token[1]][0][] = array($path, $token[2]);
    		}
    	}
    }
    function reference_dir($path, &$functions) {
    	if ($dir = opendir($path)) {
    		while (($file = readdir($dir)) !== false) {
    			if (substr($file, 0, 1) == ".") continue;
    			if (is_dir($path . "/" . $file)) {
    				reference_dir($path . "/" . $file, $functions);
    			} else {
    				if (substr($file, - 4, 4) != ".php") continue;
    				reference_file($path . "/" . $file, $functions);
    			}
    		}
    	}		
    }
    function reference_file($path, &$functions) {
    	$tokens = token_get_all(file_get_contents($path));
    	for ($i = 0; $i < count($tokens); $i++) {
    		$token = $tokens[$i];
    		if (is_array($token)) {
    			if ($token[0] != T_STRING) continue;
    			if ($tokens[$i + 1] != "(") continue;
    			$functions[$token[1]][1][] = array($path, $token[2]);
    		}
    	}
    }
?>

I'll probably spend some more time on it so I can quickly find the files and line numbers of the function definitions and references; this information is being gathered, just not displayed.

Comments