tags:

views:

1330

answers:

5

Does anyone know of a tool that can find unused functions in a php project?

I'm looking for a program that can scan a folder (and sub folders) containing php code and tell me which functions are never referenced.

+2  A: 

Try out the PHP Test Coverage Tool.

Greg Hurlman
+1  A: 

Xdebug can also provide code coverage. You could use it in combination with the autoprependfile and autoappendfile ini directives to log code coverage of your application during general use.

Dave Marshall
+4  A: 

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.

Stacey Richards
This solution is good if you never use `call_user_func()` or `call_user_func_array()` or `$var()`
calebbrown
A: 

Stacey,

I'm having the same issue. Did you ever do any more work on your script? Specifically, if I'm correct, it seems to count the function definition in the "refrences" column...

If you're still interested, I'll probably be making some modifications within the next few lines. Feel free to drop me a line - jason AT jasonNOSPACEantmanDOTcom

A: 

Modification to stop the script returning the function definition:

if ($tokens[$i - 2][1] == "function") continue;

add the above line after: if ($tokens[$i + 1] != "(") continue;

Outspaced