如何在PHP项目中找到未使用的函数

时间:2020-03-05 18:39:43  来源:igfitidea点击:

如何在PHP项目中找到任何未使用的函数?

PHP中是否有功能或者API可以让我分析代码库,例如反射,token_get_all()

这些API的功能是否足够丰富,使我不必依赖第三方工具来执行此类分析?

解决方案

回答

感谢Greg和Dave的反馈。并不是我想要的东西,但是我决定花一些时间研究它,并提出了一个快速而肮脏的解决方案:

<?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]);
            }
        }
    }
?>

我可能会花更多的时间在上面,以便可以快速找到函数定义和引用的文件和行号。该信息正在收集,只是不显示。

回答

如果我没记错的话,可以使用phpCallGraph来做到这一点。使用所有涉及的方法,它将为我们生成一个漂亮的图形(图像)。如果某个方法未与其他任何方法连接,则表明该方法是孤立的。

这是一个示例:classGallerySystem.png

方法" getKeywordSetOfCategories()"是孤立的。

顺便说一句,我们不必拍摄图像-phpCallGraph也可以生成文本文件或者PHP数组等。

回答

因为可以动态调用PHP函数/方法,所以没有确定性的方法可以永远不会调用函数。

唯一确定的方法是通过手动分析。

回答

phpxref将确定从何处调用函数以简化分析,但是仍然需要一定量的人工。

回答

afaik没有办法。要知道哪些功能"属于谁",我们需要执行系统(运行时后期绑定功能查找)。

但是重构工具是基于静态代码分析的。我真的很喜欢动态类型语言,但我认为它们很难扩展。大型代码库和动态类型化语言中缺乏安全的重构是可维护性和处理软件演进的主要缺点。