2012-03-27 43 views
11

我已經找遍了這樣的事情不使用`use`聲明,但我相信「用」字爲任何有用的結果也許是太普通了:檢測最簡單的方法/刪除PHP代碼庫

是什麼從PHP代碼庫中的類文件中刪除所有未使用的use語句的最簡單方法?

編輯:爲了簡單起見,我們可以忽略檢測用於註釋的use語句。

+0

此工具如何知道何時不使用名稱空間? – 2012-03-27 18:38:14

+1

那麼你需要收集每個use-statement,用tokenizer解析你的文件,看看它是否是實例化的或靜態調用的。但這需要一點工作。 – 2012-03-27 18:43:34

+0

我已經編輯了我的答案中的代碼,你現在應該再試一次:)。我測試了一些案例,它工作。我希望現在讓你滿意。它只適用於一個文件,但;對於較大的項目,您應該調整它,並建立一個更大的索引。 – 2012-03-28 09:44:08

回答

16

查看Fabien Potencier的PHP-CS-Fixer https://github.com/fabpot/PHP-CS-Fixer

+1

這個工具是faboo。謝謝! – yitznewton 2013-10-09 15:51:59

+4

'./php-cs-fixer修復文件夾/ --fixers = unused_use'爲我工作 – mrwaim 2015-07-24 04:37:33

+0

'./php-cs-fixer修復src/Backend/--rules = no_unused_imports'爲我做了詭計 – Kitze 2018-01-24 10:29:56

1

這可能取決於您的代碼設置的方式。如果你的代碼使用這樣的命名空間:

namespace Foo 
{ 
    <one or more classes in namespace Foo> 
} 

那麼你可能很好,如果你只是單獨檢查每個文件。這仍然意味着您將不得不解析PHP代碼以查找使用語句,然後確定使用哪些語句。

簡單的方法是使用已經構建的工具。我最近開始使用PhpStorm IDE(30天免費試用版,或early access program),並且可以通知您何時在文件中有未使用的use語句(並且您甚至可以指定是否應該將其作爲警告或錯誤)。它仍然會要求你打開每個文件。但是你也可以檢查你正在編輯的文件,最後你的代碼會更清晰。

6

編輯

我已經完全改寫了,所以現在更強大:

  • 性狀和匿名/λ功能被忽略
  • 現在照顧catch塊的,類擴展和接口
  • 縮進和註釋無關緊要
  • 命名空間的多個聲明CE別名工作太
  • 靜態和對象調用類被認定爲「使用」(U盤$> getUsages())
  • 全和半合格用途不視爲

的測試文件,類.PHP:

<?php 

use My\Full\Classname as Another, My\Full\NSname, Some\Other\Space; 

/* some insane commentary */ use My\Full\NSname1; use ArrayObject; 

$obj = new namespaced\Another; 
$obj = new Another; 

$a = new ArrayObject(array(1)); 

Space::call(); 

$a = function($a, $b, $c = 'test') use ($obj) { 
    /* use */ 
}; 

class MyHelloWorld extends Base { 
    use traits, hello, world; 
} 

這裏的腳本:

<?php 
class UseStatementSanitzier 
{ 
    protected $content; 

    public function __construct($file) 
    { 
    $this->content = token_get_all(file_get_contents($file)); 

    // we don't need and want them while parsing 
    $this->removeTokens(T_COMMENT); 
    $this->removeTokens(T_WHITESPACE); 
    } 

    public function getUnused() 
    { 
    $uses = $this->getUseStatements(); 
    $usages = $this->getUsages(); 
    $unused = array(); 

    foreach($uses as $use) { 
     if (!in_array($use, $usages)) { 
     $unused[] = $use; 
     } 
    } 
    return $unused; 
    } 

    public function getUsages() 
    { 
    $usages = array(); 

    foreach($this->content as $key => $token) { 

     if (!is_string($token)) { 
     $t = $this->content; 

     // for static calls 
     if ($token[0] == T_DOUBLE_COLON) { 
      // only if it is NOT full or half qualified namespace 
      if ($t[$key-2][0] != T_NAMESPACE) { 
      $usages[] = $t[$key-1][1]; 
      } 
     } 

     // for object instanciations 
     if ($token[0] == T_NEW) { 
      if ($t[$key+2][0] != T_NAMESPACE) { 
      $usages[] = $t[$key+1][1]; 
      } 
     } 

     // for class extensions 
     if ($token[0] == T_EXTENDS || $token[0] == T_IMPLEMENTS) { 
      if ($t[$key+2][0] != T_NAMESPACE) { 
      $usages[] = $t[$key+1][1]; 
      } 
     } 

     // for catch blocks 
     if ($token[0] == T_CATCH) { 
      if ($t[$key+3][0] != T_NAMESPACE) { 
      $usages[] = $t[$key+2][1]; 
      } 
     } 
     } 
    } 
    return array_values(array_unique($usages)); 
    } 

    public function getUseStatements() 
    { 
    $tokenUses = array(); 
    $level = 0; 

    foreach($this->content as $key => $token) { 

     // for traits, only first level uses should be captured 
     if (is_string($token)) { 
     if ($token == '{') { 
      $level++; 
     } 
     if ($token == '}') { 
      $level--; 
     } 
     } 

     // capture all use statements besides trait-uses in class 
     if (!is_string($token) && $token[0] == T_USE && $level == 0) { 
     $tokenUses[] = $key; 
     } 
    } 

    $useStatements = array(); 

    // get rid of uses in lambda functions 
    foreach($tokenUses as $key => $tokenKey) { 
     $i     = $tokenKey; 
     $char    = ''; 
     $useStatements[$key] = ''; 

     while($char != ';') { 
     ++$i; 
     $char = is_string($this->content[$i]) ? $this->content[$i] : $this->content[$i][1]; 

     if (!is_string($this->content[$i]) && $this->content[$i][0] == T_AS) { 
      $useStatements[$key] .= ' AS '; 
     } else { 
      $useStatements[$key] .= $char; 
     } 

     if ($char == '(') { 
      unset($useStatements[$key]); 
      break; 
     } 
     } 
    } 

    $allUses = array(); 

    // get all use statements 
    foreach($useStatements as $fullStmt) { 
     $fullStmt = rtrim($fullStmt, ';'); 
     $fullStmt = preg_replace('/^.+ AS /', '', $fullStmt); 
     $fullStmt = explode(',', $fullStmt); 

     foreach($fullStmt as $singleStmt) { 
     // $singleStmt only for full qualified use 
     $fqUses[] = $singleStmt; 

     $singleStmt = explode('\\', $singleStmt); 
     $allUses[] = array_pop($singleStmt); 
     } 
    } 
    return $allUses; 
    } 

    public function removeTokens($tokenId) 
    { 
    foreach($this->content as $key => $token) { 
     if (isset($token[0]) && $token[0] == $tokenId) { 
     unset($this->content[$key]); 
     } 
    } 
    // reindex 
    $this->content = array_values($this->content); 
    } 

} 

$unused = new UseStatementSanitzier('class.php'); 

print_r($unused->getUnused()); 

/* 
Returns: 
Array 
(
    [0] => NSname 
    [1] => NSname1 
) 
*/ 
+0

不錯!我會給你一個鏡頭,讓你知道它是怎麼回事。 – leek 2012-03-27 20:12:11

+1

類(用於PHP 5.4中的特性)和前面的閉包塊中的'use'指令是否具有與名稱空間'use'不同的標記類型?否則,您可能需要確保此代碼忽略這些代碼。 – FtDRbwLXw6 2012-03-27 22:57:14

+0

好的,我知道,我已經忘記了一些情況,我很快就會對代碼做些修改。 – 2012-03-28 06:25:43

相關問題