English 中文(简体)
是否有一个PHP改造工具来说明哪些职能从未被称作? [复制]
原标题:Is there a PHP refactoring tool to tell what functions are never called? [duplicate]

我如何在项目组合中找到任何未使用的职能?

是否在PHP中设置了某些特征或标语,使我能够分析我的代码基——例如Reflection,/<>>/a>?

这些意向书是否丰富,使我不必依赖第三方工具进行这种分析?

最佳回答

感谢格雷瓜和达维反馈。 我所期待的是多少,但我决定为研究研究留出一定时间,并提出这一迅速和 d脏的解决办法:

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

我很可能花了更多的时间,以便我能够迅速找到职能定义和参考资料的档案和线号;这一信息正在收集,只是没有显示。

问题回答

script脚本可以帮助:

grep -rhio ^function .*(  .|awk -F [( ]    {print "echo -n " $2 " && grep -rin " $2 " .|grep -v function|wc -l"} |bash|grep 0

这基本上重复了目前职能定义的目录,把打到了瓦克,这构成了以下指挥:

  • print the function name
  • recursively grep for it again
  • piping that output to grep -v to filter out function definitions so as to retain calls to the function
  • pipes this output to wc -l which prints the line count

之后,该指挥部被派去执行,产出为零,这表明该职能有0个电话。

请注意,这将而不是解决上文所引述的问题,因此,在产出方面可能有一些错误的肯定。

USAGE: find_un used_Functions.php <root_directory>

NOTE: This is a `quick-n-dirty' approach to the problem. 该书仅对档案进行灵活处理,不尊重不同单元界定相同名称的职能或方法的情况。 如果你利用国际民主和选举援助学会来开发你的植物检疫和植物检疫,那么,它可能提供更全面的解决办法。

所需PHP 5月

为节约一份复印件和过去,直接下载和任何新版本如下:<>

#!/usr/bin/php -f
 
<?php
 
// ============================================================================
//
// find_unused_functions.php
//
// Find unused functions in a set of PHP files.
// version 1.3
//
// ============================================================================
//
// Copyright (c) 2011, Andrey Butov. All Rights Reserved.
// This script is provided as is, without warranty of any kind.
//
// http://www.andreybutov.com
//
// ============================================================================
 
// This may take a bit of memory...
ini_set( memory_limit ,  2048M );
 
if ( !isset($argv[1]) ) 
{
    usage();
}
 
$root_dir = $argv[1];
 
if ( !is_dir($root_dir) || !is_readable($root_dir) )
{
    echo "ERROR:  $root_dir  is not a readable directory.
";
    usage();
}
 
$files = php_files($root_dir);
$tokenized = array();
 
if ( count($files) == 0 )
{
    echo "No PHP files found.
";
    exit;
}
 
$defined_functions = array();
 
foreach ( $files as $file )
{
    $tokens = tokenize($file);
 
    if ( $tokens )
    {
        // We retain the tokenized versions of each file,
        // because we ll be using the tokens later to search
        // for function  uses , and we don t want to 
        // re-tokenize the same files again.
 
        $tokenized[$file] = $tokens;
 
        for ( $i = 0 ; $i < count($tokens) ; ++$i )
        {
            $current_token = $tokens[$i];
            $next_token = safe_arr($tokens, $i + 2, false);
 
            if ( is_array($current_token) && $next_token && is_array($next_token) )
            {
                if ( safe_arr($current_token, 0) == T_FUNCTION )
                {
                    // Find the  function  token, then try to grab the 
                    // token that is the name of the function being defined.
                    // 
                    // For every defined function, retain the file and line
                    // location where that function is defined. Since different
                    // modules can define a functions with the same name,
                    // we retain multiple definition locations for each function name.
 
                    $function_name = safe_arr($next_token, 1, false);
                    $line = safe_arr($next_token, 2, false);
 
                    if ( $function_name && $line )
                    {
                        $function_name = trim($function_name);
                        if ( $function_name != "" )
                        {
                            $defined_functions[$function_name][] = array( file  => $file,  line  => $line);
                        }
                    }
                }
            }
        }
    }
}
 
// We now have a collection of defined functions and
// their definition locations. Go through the tokens again, 
// and find  uses  of the function names. 
 
foreach ( $tokenized as $file => $tokens )
{
    foreach ( $tokens as $token )
    {
        if ( is_array($token) && safe_arr($token, 0) == T_STRING )
        {
            $function_name = safe_arr($token, 1, false);
            $function_line = safe_arr($token, 2, false);;
 
            if ( $function_name && $function_line )
            {
                $locations_of_defined_function = safe_arr($defined_functions, $function_name, false);
 
                if ( $locations_of_defined_function )
                {
                    $found_function_definition = false;
 
                    foreach ( $locations_of_defined_function as $location_of_defined_function )
                    {
                        $function_defined_in_file = $location_of_defined_function[ file ];
                        $function_defined_on_line = $location_of_defined_function[ line ];
 
                        if ( $function_defined_in_file == $file && 
                             $function_defined_on_line == $function_line )
                        {
                            $found_function_definition = true;
                            break;
                        }
                    }
 
                    if ( !$found_function_definition )
                    {
                        // We found usage of the function name in a context
                        // that is not the definition of that function. 
                        // Consider the function as  used .
 
                        unset($defined_functions[$function_name]);
                    }
                }
            }
        }
    }
}
 
 
print_report($defined_functions);   
exit;
 
 
// ============================================================================
 
function php_files($path) 
{
    // Get a listing of all the .php files contained within the $path
    // directory and its subdirectories.
 
    $matches = array();
    $folders = array(rtrim($path, DIRECTORY_SEPARATOR));
 
    while( $folder = array_shift($folders) ) 
    {
        $matches = array_merge($matches, glob($folder.DIRECTORY_SEPARATOR."*.php", 0));
        $moreFolders = glob($folder.DIRECTORY_SEPARATOR. * , GLOB_ONLYDIR);
        $folders = array_merge($folders, $moreFolders);
    }
 
    return $matches;
}
 
// ============================================================================
 
function safe_arr($arr, $i, $default = "")
{
    return isset($arr[$i]) ? $arr[$i] : $default;
}
 
// ============================================================================
 
function tokenize($file)
{
    $file_contents = file_get_contents($file);
 
    if ( !$file_contents )
    {
        return false;
    }
 
    $tokens = token_get_all($file_contents);
    return ($tokens && count($tokens) > 0) ? $tokens : false;
}
 
// ============================================================================
 
function usage()
{
    global $argv;
    $file = (isset($argv[0])) ? basename($argv[0]) : "find_unused_functions.php";
    die("USAGE: $file <root_directory>

");
}
 
// ============================================================================
 
function print_report($unused_functions)
{
    if ( count($unused_functions) == 0 )
    {
        echo "No unused functions found.
";
    }
 
    $count = 0;
    foreach ( $unused_functions as $function => $locations )
    {
        foreach ( $locations as $location )
        {
            echo " $function  in {$location[ file ]} on line {$location[ line ]}
";
            $count++;
        }
    }
 
    echo "=======================================
";
    echo "Found $count unused function" . (($count == 1) ?    :  s ) . ".

";
}
 
// ============================================================================
 
/* EOF */

2020 Update

我使用了上文概述的其他方法,甚至“2019”的更新回答是过时的

Tomáš Votruba的回答导致我发现Phan,因为ECS的路线现已被拆除。 修补已清除了死者的公共方法检查器。

Phan is a static analyzer for PHP

我们可以利用Phan寻找死亡法典。 这里的步骤是使用堆肥装置。 这些步骤还见git repo for phan。 这些指示是你项目的根源。

Step 1 - Install Phan w/ composer

composer require phan/phan

Step 2 - Install php-ast

PHP-AST is a requirement for Phan As I m using WSL, I ve been able to use PECL to install, however, other install methods for php-ast can be found in a git repo

pecl install ast

Step 3 - Locate and edit php.ini to use php-ast

Loate current php.ini

php -i | grep  php.ini 

如今,该档案站和纳米(或你选择的那儿)。 划定所有延伸区和阿DD线如下:

extension=ast.so

Step 4 - create a config file for Phan

Steps on config file can be found in Phan s documentation on how to create a config file You ll want to use their sample one as it s a good starting point. Edit the following arrays to add your own paths on both directory_list & exclude_analysis_directory_list. Please note that exclude_analysis_directory_list will still be parsed but not validated eg. adding Wordpress directory here would mean, false positives for called wordpress functions in your theme would not appear as it found the function in wordpress but at the same time it ll not validate functions in wordpress folder. Mine looked like this

......

 directory_list  => [
   public_html 
],

......

 exclude_analysis_directory_list  => [
     vendor/ ,
     public_html/app/plugins ,
     public_html/app/mu-plugins ,
     public_html/admin 
],
......

Step 5 - Run Phan with dead code detection

现在,我们安装了甲和乙醇,把我们所希望的 par子混为一谈,现在需要时间来管理Phan。 我们将向phan-dead-code-detection提出论据。 这是不言而喻的。

./vendor/bin/phan --dead-code-detection

这需要与<_____________>核查,但需要与“否”核查。

产出将视之为ole。

the/path/to/php/file.php:324 PhanUnreferencedPublicMethod Possibly zero references to public method	hepath	ofunction::the_funciton()
the/path/to/php/file.php:324 PhanUnreferencedPublicMethod Possibly zero references to public method	hepath	ofunction::the_funciton()
the/path/to/php/file.php:324 PhanUnreferencedPublicMethod Possibly zero references to public method	hepath	ofunction::the_funciton()
the/path/to/php/file.php:324 PhanUnreferencedPublicMethod Possibly zero references to public method	hepath	ofunction::the_funciton()

请自由补充或纠正我的错误:

由于购买力平价的功能/方法可以有活力地加以利用,因此没有方案方式可以肯定地知道是否永远不会要求职能。

唯一一种办法是通过人工分析。

phpxref,将确定哪些职能可以促进分析,但还有一定数量的人工努力。

afaik没有办法。 • 了解“属于谁”哪些职能需要执行这一制度(时间过晚的具有约束力的职能审查)。

但辅助工具基于静态编码分析。 我真像充满活力的类型语言,但我认为,这些语言难以推广。 大型密码库和动态型语文缺乏安全因素,是维持和处理软件演变的一个主要缺陷。





相关问题
Brute-force/DoS prevention in PHP [closed]

I am trying to write a script to prevent brute-force login attempts in a website I m building. The logic goes something like this: User sends login information. Check if username and password is ...

please can anyone check this while loop and if condition

<?php $con=mysql_connect("localhost","mts","mts"); if(!con) { die( unable to connect . mysql_error()); } mysql_select_db("mts",$con); /* date_default_timezone_set ("Asia/Calcutta"); $date = ...

定值美元

如何确认来自正确来源的数字。

Generating a drop down list of timezones with PHP

Most sites need some way to show the dates on the site in the users preferred timezone. Below are two lists that I found and then one method using the built in PHP DateTime class in PHP 5. I need ...

Text as watermarking in PHP

I want to create text as a watermark for an image. the water mark should have the following properties front: Impact color: white opacity: 31% Font style: regular, bold Bevel and Emboss size: 30 ...

How does php cast boolean variables?

How does php cast boolean variables? I was trying to save a boolean value to an array: $result["Users"]["is_login"] = true; but when I use debug the is_login value is blank. and when I do ...