Phan は、誤検知を最小限に抑えることを好む PHP 用の静的アナライザーです。ファンは正しさよりも不正確さを証明しようとします。
Phan は一般的な問題を探し、型情報が利用可能または推定できる場合には、さまざまな操作で型の互換性を検証します。 Phan はフロー制御についてよく (しかし包括的ではありませんが) 理解しており、いくつかの使用例 (配列、整数、文字列など) で値を追跡できます。
Phan を使用する最も簡単な方法は、Composer を使用することです。
composer require phan/phan
Phan がインストールされたら、プロジェクト内に.phan/config.php
ファイルを作成して、ソース コードの分析方法を Phan に指示します。構成が完了すると、 ./vendor/bin/phan
経由で実行できます。
Phan 5 は、php-ast 拡張機能 (1.1.1 以降が推奨) を備えた PHP 7.2 以降に依存し、PHP バージョン 7.0 ~ 8.2 の構文の分析をサポートします。 php-ast のインストール手順はここにあります。 (Phan は、CLI オプション--allow-polyfill-parser
使用することで php-ast なしで使用できますが、ドキュメント コメントの解析には若干の違いがあります)
Phan の使用に関する詳細については、Wiki を参照してください。
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 から使用できます。エディターとツールは、よりシンプルなデーモン モードを使用して、プロジェクト内の個々のファイルの分析を要求することもできます。
さまざまなチェックの例については、tests ディレクトリを参照してください。
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 は、ユニオン型 ( int|MyClass|string|null
など) や汎用配列型 ( int[]
またはstring[]|MyClass[]
またはarray<int,MyClass>
など) を含むほとんどの PHPDoc 型アノテーションを読み取って理解します。
コード内で型を定義する方法については、「ソース コードの注釈付け」および「ユニオン型について」を参照してください。
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>
として表すことを意味します。 array<int,int>|array<int,string>
。 [$strKey => new MyClass(), $strKey2 => $unknown]
はarray<string,MyClass>|array<string,mixed>
として表されます。
[12,'myString']
などのリテラルは、内部ではarray{0:12,1:'myString'}
などの配列形状として表されます。この静的アナライザーは、インクルードを追跡したり、オートローダーの魔法を理解しようとしたりしません。投げられたすべてのファイルを 1 つの大きなアプリケーションとして扱います。クラスにカプセル化されたコードの場合、これはうまく機能します。グローバル スコープで実行されるコードの場合、順序が重要になるため、少し難しくなります。多数のグローバル変数を設定するファイルを含むindex.php
があり、 index.php
のinclude(...)
の後にそれらの変数にアクセスしようとしても、静的アナライザーはこれらについて何も認識しません。
実際には、これは単純に、エントリ ポイントとグローバル スコープに設定するファイルをファイル リストの先頭に置く必要があることを意味します。他のすべてに必要なグローバル変数を設定するconfig.php
がある場合は、それをリストの最初に追加し、その後にさまざまなエントリ ポイントを追加し、次にクラスを含むすべてのライブラリ ファイルを追加する必要があります。
Phan のハッキングを始めるにあたっては、「Developer's Guide to Phan」を参照してください。
問題を見つけたら、時間をかけてバグを説明する小さな再現コード スニペットを作成してください。それが完了したら、修正してください。次に、コード スニペットをテストに変換し、テストに追加してから./test
実行し、修正とテストを含む PR を送信します。または、詳細を含む問題を開くこともできます。
Phan の単体テストを実行するには、 ./test
を実行するだけです。
Phan のすべての単体テストと統合テストを実行するには、 ./tests/run_all_tests.sh
run_all_tests.sh を実行します。
私たちは、居心地の良いコミュニティの育成に取り組んでいます。参加者および寄稿者は、当社の行動規範を遵守する必要があります。
これには、Firefox/Chrome の最新バージョンと、少なくとも 4 GB の空き RAM が必要です。 (これは 15 MB のダウンロードです)
Phan を完全にブラウザ内で実行します。