Page 1
PHP静的解析現状確認会
ピクシブ株式会社 / pixiv.git
pixiv Inc.
うさみけんた / tadsan
2019-02-18
公開日:
by USAMI Kenta @tadsan
にオンラインのビデオ会議で開催された『PHP静的解析現状確認会』発表しました。
PHP静的解析現状確認会
ピクシブ株式会社 / pixiv.git
pixiv Inc.
うさみけんた / tadsan
2019-02-18
はじめに
現状を三行で
2540
自己紹介
以前にやってた言語は
●
PHP Ruby, sh, Lisp
経験として動的言語が中心
○
静的型は に触れた程度
○
F#, OCaml, Haskell
年 月にピクシブ入社最初は
●
2012 11 ( Ruby)
年 月頃から を書きはじめた
●
2013 4 PHP
tadsan
運営本部
pixiv
2540
のコードベースの特徴
pixiv
手続き型に大きく寄った設計志向・アンチ の傾向が近い
●
OOP
クラスはオートロード可能な関数と定数の置き場としての扱い
○
から取得した値をそのまま扱うことが多いので連想配列を多用
○
PDO
旧来の手法≒ による静的解析を容易にするためのコードベース
●
( grep)
文字列・配列による 表現はクロージャで表現する
●
callable
を採用していない による別名使用は極力しない
●
PSR-4 (use )
2540
と静的解析
pixiv
たぶん 年頃 デプロイ時に必ず でのチェックを実施
●
( 2014 ) php -l
それ以前は を含むファイルをデプロイすることがまれにあった
○
SyntaxError
年 月正規表現ベースの を導入
●
2016 3 : lint
の 単位で される度に実行・コメント
○
GitLab MR push
年頃から 検証 静的解析がもたらす大 型検査時代
● →
2016 Phan Phan PHP
(phpcon2016)
年 月 を本格的に に導入
●
2018 6 : PHPStan CI
2540
に寄らない利点
OOP
この利点は と による静的解析によっておよそ無効化された。よって
●
PhpStorm PHPStan
軽々に他者に推奨する戦略ではない。
インスタンス化 メソッド呼び出しの過程を経ると、 などの
● →
grep/sed/awk
プリミティブなテキスト編集ツールだけではメソッド利用箇所の洗い出しやリファクタリング の妨げとなる。この状況は既に大量のコードがあるプロジェクトを効率よくメンテする側面
においては大変に痛かった。
繰り返すが、現在においては型と静的解析の力を利用しながら のリファクタリ
●
PhpStorm
ング機能などを利用し、過不足にほかのツールを利用するの懸命だろう
2540
正規表現ベースのチェッカー
(linter)
適用するパターン・除外するパターンを書ける
●
では との のあったファイルに対してチェッカーを適用
●
MR master diff
推奨されないバッドノウハウや表記揺れなどを抑止する目的
●
除外パターンも書けるので特定の場合のみ例外的に許可もしやすい
●
例 テストコードでのみ使用可
○
:
パターンのテストもあるのでチームメンバーが必要に応じて加除
●
2540
'@pixiv-lib/.*\.php$@' => [
[
'level' => 'error',
で定義されているクラスは しないこと
'desc' => 'pixiv-lib include_once ',
'pattern' => [
'/include_once[ \(] *INC_PATH /' => false,
'@/stacc/api\.php@' => true,
],
'tests' => [
['pixiv-lib/foo.php', "include_once INC_PATH . '/Awesome/Class.php';",
true],
['pixiv-lib/foo.php', "include_once INC_PATH . '/stacc/api.php';",
false],
['pixiv-lib/foo.php', "include_once INC_PATH . 'HogeClass.php';", true],
['foo.php', "include_once INC_PATH . '/Awesome/Class.php';", false],
['foo.php', "include_once INC_PATH . '/stacc/api.php';", false], ['foo.php', "include_once INC_PATH . 'HogeClass.php';", false],
],
],
],
2540
Phan
コードを強力に静的解析する
●
連想配列の要素や特定のリテラルが来ること期待して解析できる
●
@phan-return array{mode:’foo’|’bar’,hoge:string}
○
明示しなくても実行パスを収集して最大限に型を推論してくれる
○
解析の度に全コードをスキャンするので大規模なコードベースでは、
●
とても時間がかかる
2540
PHPStan
コードを強力に解析するが、静的情報だけではなく実行時情報を活用する
●
正確に検査するためには解析対象をオートロードあるいは事前読み込みできるようにす
●
( )
ることが前提
一回のプロセス起動で多数のファイルを同時に解析すると多量のメモリを消費するので、
●
と違ってプロジェクトの全クラスを一度に検査する用途は向かない
Phan
2540
の
pixiv CI
および のテストによる動的解析と
●
PHPUnit( JS )
と正規表現ベースの による静的解析の二本立て
PHPStan linter
前述の通り、静的解析には ではなく を採用している
●
Phan PHPStan
実行環境の改善により、 の における のブ
●
CI GitLab Merge Request(GitHub Pull Request)
ランチに してから 秒前後で動的解析と静的解析の結果が得られる
push 60
2540
と型
PHP
2540
アプリケーションと型
PHP
そもそもが動的型付け言語で、静的に型を付ける上で不利な面も多い
●
時などは、
ATTR_EMULATE_PREPARES
● $_GET $_POST PDO
, , ( )
あらゆる値を文字列型または再帰的に文字列を要素とする配列として扱う
( )
そのような値に対して「適切なキャスト」を書くのは「とても」難しい
○
不用意な判定で にキャストするのはバグや脆弱性の温床になる
string->int
○
の型宣言はデフォルトでキャストするので強いリスクがある
○
PHP7
が必須
declare(strict_types=1);
( )
2540
型宣言への態度
既存の大規模なプロジェクトへの適用には強い懸念がある
●
特に のキャストが発生するケース
●
string->int
設定済みなら 処理系が、
declare(strict_types=1)
○
PHP
未設定なら人間が不用意にキャストしてしまうことがある
新規のプロジェクトでも、値を適切に扱える環境で慎重に導入したい
●
ではスカラー型宣言 は利用せず に留めたい
●
pixiv (int, string, bool) PHPDoc
2540
ちょっと気になってるけど使ってない
●
https://github.com/sensiolabs-de/deptrac
●
https://github.com/vimeo/psalm