PHP 프로젝트에서 사용하지 않는 함수를 찾으려면 어떻게 해야 하나요?
Reflection]1, token_get_all()
와 같이 코드베이스를 분석할 수 있는 기능이나 API가 PHP에 내장되어 있나요?
이러한 API는 이러한 유형의 분석을 수행하기 위해 타사 도구에 의존하지 않아도 될 만큼 기능이 풍부합니까?
>. 불필요한 코드 '는' 파프드스트 검출기 (DCD) 의 PHP 코드. Php 는 프로젝트의 선언된 모든 함수 및 메서드 및 보고서 검색하여 cerner 部门是这样的 " 죽은입니다 code"; 불렀으매 않는 한 번 이상.
출처: https://github.com/sebastianbergmann/phpdcd
참고로 it& 부여할 수 있기 때문에, 정적 코드 s # 39 만 호출됨 무중단으로 대한 거짓값 포지티브 어낼라이저 메서드입니다 foo $ = & # 39 fn& 탐지합니다 없습니다 ' (예: # 39;;; 'foo $ ();
Pear 통해 이를 설치할 수 있습니다.
pear install phpunit/phpdcd-beta
그 후 다음 옵션과 함께 사용할 수 있습니다.
Usage: phpdcd [switches] <directory|file> ...
--recursive Report code as dead if it is only called by dead code.
--exclude <dir> Exclude <dir> from code analysis.
--suffixes <suffix> A comma-separated list of file suffixes to check.
--help Prints this usage information.
--version Prints the version and exits.
--verbose Print progress bar.
더 많은 도구.
, 리포지토리를 Note: 따라 이 사업은 계속 유지되고, 그 밖에 더 이상 디이브이 리포지토리를 보관 용도로 . 따라서, 마일리지 다를 수 있습니다.
피드백을 주신 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]);
}
}
}
?>
함수 정의와 참조의 파일과 줄 번호를 빠르게 찾을 수 있도록 좀 더 시간을 들여서 이 정보를 수집 중이지만 표시되지 않을 뿐입니다.
이 배시 스크립팅하는 조금이라도 도움이 됩니다.
grep -rhio ^function\ .*\( .|awk -F'[( ]' '{print "echo -n " $2 " && grep -rin " $2 " .|grep -v function|wc -l"}'|bash|grep 0
기본적으로 이 함수 정의, awk, 현재 디렉터리에 반복적으로 그렙 통과할 안타에 명령을 형성하는 다음 작업을 수행할 수 있습니다.
이 명령은 시연장에 전송할 수 있는 그레프트 실행을 위해 bash 및 출력이 0 0 에 대해 함수 나타낼 수 있다.
참고로 이 문제를 해결할 수 있으므로, 있을 수 없는 거역한다면 비유하사 케일럽 브라운 위에 있는 일부 거짓값 포지티브 출력입니다.
사용법: , , gt root_directory& find_unused_functions.php & lt;;
참고: 이는 "빠른 ᄂ씨 더러운" 접근 방식이 아니다. 이 상황을 통해 전달하십시오 파일이므로 스크립트만 는 사전적 정의 함수 또는 메서드을 같은 이름의 다른 모듈에서는 존중하십시오 않습니다. Php 개발 IDE 를 사용하는 경우, 그것은 더 포괄적인 솔루션을 제공할 수 있습니다.
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.\n";
usage();
}
$files = php_files($root_dir);
$tokenized = array();
if ( count($files) == 0 )
{
echo "No PHP files found.\n";
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>\n\n");
}
// ============================================================================
function print_report($unused_functions)
{
if ( count($unused_functions) == 0 )
{
echo "No unused functions found.\n";
}
$count = 0;
foreach ( $unused_functions as $function => $locations )
{
foreach ( $locations as $location )
{
echo "'$function' in {$location['file']} on line {$location['line']}\n";
$count++;
}
}
echo "=======================================\n";
echo "Found $count unused function" . (($count == 1) ? '' : 's') . ".\n\n";
}
// ============================================================================
/* EOF */
제 기억이 맞다면 phpCallGraph을 사용하여 그렇게 할 수 있습니다. 그러면 관련된 모든 메소드가 포함된 멋진 그래프(이미지)가 생성됩니다. 어떤 메소드가 다른 메소드에 연결되어 있지 않다면, 그 메소드가 고아라는 좋은 신호입니다.
다음은 예시입니다: classGallerySystem.png
getKeywordSetOfCategories()` 메서드는 고아 상태입니다.
참고로, 이미지를 가져올 필요는 없습니다. phpCallGraph는 텍스트 파일이나 PHP 배열 등을 _생성_할 수도 있습니다.
나는 attaboy 제프리드 에서 [Andrey& # 39 의 오토메이티드] (https://stackoverflow.com/questions/11532/how-can-i-find-unused-functions-in-a-php-project/7133253 # 7133253) 이 붙여넣습니다 코딩 표준 및 켜졌음 sniff.
탐지 매우 간단하면서도 강력한:
모든 방법을 aspt 공적인 기능은 섬메트로트 () '-'
이 날 수 있도록 지루려면 [끝날거요] (https://github.com/Symplify/Symplify/commit/fa21855694d933716117b2a2db13acac55b86d69) [20+ 방법] (https://github.com/Symplify/Symplify/commit/3f08ed1fb2f22dd6c4a7b46d680adf4ab5a0907d) 나 유지 및 테스트 할 것입니다.
< br>;
설치처 ECS:
composer require symplify/easy-coding-standard --dev
'설정' 에치오야마라 구성:
# ecs.yaml
services:
Symplify\CodingStandard\Sniffs\DeadCode\UnusedPublicMethodSniff: ~
명령을 실행합니다.
vendor/bin/ecs check src
여기에 대한 자세한 내용을 확인할 수 있습니다. < ";;; a href = " (https://www.tomasvotruba.cz/blog/2019/03/14/remove-dead-public-methdos-from-your-code/) 에서 공개 메서드을 죽은입니다 제거하시겠습니까 > code< /a>;
아파이크 길이 없다. 알 수 있는 기능, whom" 속하는 " 있다. 실행하십시오 시스템 (런타임용으로 개발하십시오 바인딩하면 말 함수은 조회) 을 사용해야 합니다.
그러나 리팩토링 도구를 기준으로 그룹화됩니다 정적 프로그램 분석. 하지만 제가 보기에 이들은 어려운 언어, i really like 동적임 입력되었는지 배율입니다. 안전 및 동적 언어가 부족하다는 단점이 유지 관리에 대한 대규모 코드 리팩토링 입력되었는지 주요 소프트웨어, 취급료 진화.