Phan 是 PHP 的靜態分析器,它更願意最大限度地減少誤報。潘試圖證明錯誤而不是正確。
Phan 尋找常見問題,並在類型資訊可用或可以推斷時驗證各種操作的類型相容性。 Phan 對流量控制有很好的(但不全面)理解,並且可以追蹤一些用例中的值(例如陣列、整數和字串)。
使用 Phan 最簡單的方法是透過 Composer。
composer require phan/phan
安裝 Phan 後,您需要在專案中建立一個.phan/config.php
檔案來告訴 Phan 如何分析原始程式碼。配置完成後,您可以透過./vendor/bin/phan
運行它。
Phan 5 依賴具有 php-ast 擴充功能的 PHP 7.2+(首選 1.1.1+),並支援分析 PHP 7.0-8.2 版本語法。可以在此處找到 php-ast 的安裝說明。 (Phan 可以在沒有 php-ast 的情況下使用 CLI 選項--allow-polyfill-parser
,但在解析文件註解時略有不同)
Wiki 有更多關於使用 Phan 的資訊。
Phan 能夠執行以下類型的分析:
object
、 void
、 iterable
、 ?T
、 [$x] = ...;
、負字串偏移量、多個異常捕獲等)--dead-code-detection
)--unused-variable-detection
)--redundant-condition-detection
)use
語句。這些問題和其他一些問題類型可以使用--automatic-fix
自動修復。@template
)。int[]
、 UserObject[]
、 array<int,UserObject>
等。array{key:string,otherKey:?stdClass}
等(內部和 PHPDoc 標籤中)這也支援透過array{requiredKey:string,optionalKey?:string}
指示陣列形狀的欄位是可選的(對於@param
有用)@deprecated
註解來棄用類別、方法和函數@internal
註解作為定義它的套件的內部元素。@suppress <ISSUE_TYPE>
註解來抑制問題。@property <union_type> <variable_name>
)@method <union_type> <method_name>(<union_type> <param1_name>)
)class_alias
註釋(實驗性的,預設關閉)@phan-closure-scope
指示閉包將綁定到的類別(範例)array_map
、 array_filter
和其他內部陣列函數的閉包和傳回類型。pcntl
)請參閱 Phan 問題類型,以了解 Phan 可以偵測到的所有問題的描述和範例。查看 PhanIssue 以查看每種錯誤類型的定義。
查看分析大型草率程式碼庫的教學課程,了解持續分析的過程對您來說可能是什麼樣的。
Phan 可以透過語言伺服器協定在各種編輯器和 IDE 中使用,以進行錯誤檢查、「轉到定義」支援等。編輯器和工具還可以使用更簡單的守護程序模式請求對專案中的各個文件進行分析。
有關各種檢查的一些範例,請參閱測試目錄。
Phan 並不完美,不應該用來證明您的基於 PHP 的火箭導引系統沒有缺陷。
插件提供了額外的分析功能。
{ throw new Exception("Message"); return $value; }
)*printf()
格式字串(以及檢查常見錯誤)preg_*()
的 PCRE 正規表示式是否有效@suppress
註釋。範例:Phan 的自我分析外掛程式。
安裝 Phan 後,Phan 需要配置有關在哪裡查找要分析的程式碼以及如何分析程式碼的詳細資訊。告訴 Phan 在哪裡可以找到原始程式碼最簡單的方法是建立一個.phan/config.php
檔案。一個簡單的.phan/config.php
檔案可能如下所示。
<?php
/ * *
* This configuration will be read and overlaid on top of the
* default configuration . Command line arguments will be applied
* after this file is read .
* /
return [
// Supported values : `'5.6'` , `'7.0'` , `'7.1'` , `'7.2'` , `'7.3'` , `'7.4'` ,
// `'8.0'` , `'8.1'` , `'8.2'` , `'8.3'` , `null` .
// If this is set to `null` ,
// then Phan assumes the PHP version which is closest to the minor version
// of the php executable used to execute Phan .
" target_php_version " => null ,
// A list of directories that should be parsed for class and
// method information . After excluding the directories
// defined in exclude_analysis_directory_list , the remaining
// files will be statically analyzed for errors .
//
// Thus , both first - party and third - party code being used by
// your application should be included in this list .
' directory_list ' => [
' src ' ,
' vendor/symfony/console ' ,
],
// A directory list that defines files that will be excluded
// from static analysis , but whose class and method
// information should be included .
//
// Generally , you ' ll want to include the directories for
// third - party code ( such as "vendor/" ) in this list .
//
// n . b .: If you ' d like to parse but not analyze 3 rd
// party code , directories containing that code
// should be added to the `directory_list` as
// to `exclude_analysis_directory_list` .
" exclude_analysis_directory_list " => [
' vendor/ '
],
// A list of plugin files to execute .
// Plugins which are bundled with Phan can be added here by providing their name
// ( e . g . 'AlwaysReturnPlugin' )
//
// Documentation about available bundled plugins can be found
// at https : // github . com / phan / phan / tree / v5 / . phan / plugins
//
// Alternately , you can pass in the full path to a PHP file
// with the plugin ' s implementation .
// ( e . g . 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php' )
' plugins ' => [
// checks if a function , closure or method unconditionally returns .
// can also be written as 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'
' AlwaysReturnPlugin ' ,
' DollarDollarPlugin ' ,
' DuplicateArrayKeyPlugin ' ,
' DuplicateExpressionPlugin ' ,
' PregRegexCheckerPlugin ' ,
' PrintfCheckerPlugin ' ,
' SleepCheckerPlugin ' ,
// Checks for syntactically unreachable statements in
// the global scope or function bodies .
' UnreachableCodePlugin ' ,
' UseReturnValuePlugin ' ,
' EmptyStatementListPlugin ' ,
' LoopVariableReusePlugin ' ,
],
];
有關更多詳細信息,請參閱建立設定檔和增量強化分析。
運行phan --help
將顯示使用資訊和命令列選項。
Phan 可以閱讀並理解大多數 PHPDoc 類型註釋,包括聯合類型(如int|MyClass|string|null
)和通用數組類型(如int[]
或string[]|MyClass[]
或array<int,MyClass>
)。
請查看註釋原始程式碼和關於聯合類型,以取得在程式碼中定義類型的一些協助。
Phan 支援(int|string)[]
樣式註釋,並在內部將它們表示為int[]|string[]
(這兩個註釋都被視為可能包含整數和/或字串的陣列)。當您有混合類型的陣列時,只需使用array
。
以下程式碼顯示了支援的各種註解。
/ * *
* @ return void
* /
function f () {}
/ * * @ deprecated * /
class C {
/ * * @ var int * /
const C = 42 ;
/ * * @ var string [] | null * /
public $ p = null ;
/ * *
* @ param int | null $ p
* @ return string [] | null
* /
public static function f ( $ p ) {
if ( is_null ( $ p )) {
return null ;
}
return array_map (
/ * * @ param int $ i * /
function ( $ i ) {
return " thing $ i " ;
},
range ( 0 , $ p )
);
}
}
就像在 PHP 中一樣,任何類型都可以在函數宣告中為 null,這也表示允許為該參數傳入 null。
Phan 檢查陣列每個元素的類型(包括鍵和值)。實際上,這意味著[$int1=>$int2,$int3=>$int4,$int5=>$str6]
被視為array<int,int|string>
, Phan 表示為array<int,int>|array<int,string>
。 [$strKey => new MyClass(), $strKey2 => $unknown]
將表示為array<string,MyClass>|array<string,mixed>
。
[12,'myString']
之類的文字將在內部表示為數組形狀,如array{0:12,1:'myString'}
此靜態分析器不會追蹤包含或嘗試找出自動載入器的魔力。它將您扔給它的所有文件視為一個大應用程式。對於封裝在類別中的程式碼來說,這很有效。對於在全域範圍內運行的程式碼,它會變得有點棘手,因為順序很重要。如果您有一個index.php
其中包含一個設定一堆全域變數的文件,然後您嘗試在index.php
中的include(...)
之後存取這些變量,則靜態分析器將不會了解這些變數。
實際上,這只是意味著您應該將入口點和全域範圍內的任何檔案設定放在檔案清單的頂部。如果您有一個config.php
設定其他所有需要的全域變量,那麼您應該將其放在列表中的第一個,然後是各種入口點,然後是包含類別的所有庫檔案。
請參閱 Phan 開發人員指南,以取得開始對 Phan 進行駭客攻擊的協助。
當您發現問題時,請花時間建立一個小的重現程式碼片段來說明該錯誤。一旦你做到了這一點,就修復它。然後將您的程式碼片段轉換為測試並將其添加到測試中,然後./test
並發送包含您的修復和測試的 PR。或者,您可以開啟一個包含詳細資訊的問題。
要執行 Phan 的單元測試,只需執行./test
。
若要執行 Phan 的所有單元測試和整合測試,請執行./tests/run_all_tests.sh
我們致力於營造一個熱情的社區。任何參與者和貢獻者都必須遵守我們的行為準則。
這需要最新版本的 Firefox/Chrome 和至少 4 GB 的可用 RAM。 (這是一個 15 MB 的下載)
完全在瀏覽器中運行 Phan。