PHP静的解析現状確認会 - pixiv.git

公開日:

オンラインビデオ会議で開催された『PHP静的解析現状確認会』発表しました。

Download PDF

スライドテキスト

Page 1

PHP静的解析現状確認会

ピクシブ株式会社 / pixiv.git

pixiv Inc.
うさみけんた / tadsan

2019-02-18

Page 2

はじめに

  • 今回紹介するpixivの開発環境の改善は歴代の複数のチームメンバーの創意工夫の積み重ねであり、この資料は筆者(@tadsan)がその成果をまとめたものである
  • PHPの型に関する見解は@tadsan個人の意見およびチーム内での議論に基く

Page 3

現状を三行で

  • 未定義クラス・メソッド・定数・変数などの使用は簡単に検出できます
  • PhpStorm、PhanやPHPStanなどのツールがありますが、それぞれの特徴が
  • pixiv.gitの開発ではPull Requestごとに動的解析と静的解析の結果は概ね60秒程度で結果を表示できてます

Page 4

2540

自己紹介

以前にやってた言語は

PHP Ruby, sh, Lisp
経験として動的言語が中心

静的型は に触れた程度

F#, OCaml, Haskell

年 月にピクシブ入社最初は

2012 11 ( Ruby)
年 月頃から を書きはじめた

2013 4 PHP

tadsan
運営本部

pixiv

Page 5

2540

のコードベースの特徴

pixiv

手続き型に大きく寄った設計志向・アンチ の傾向が近い

OOP

クラスはオートロード可能な関数と定数の置き場としての扱い

から取得した値をそのまま扱うことが多いので連想配列を多用

PDO

旧来の手法≒ による静的解析を容易にするためのコードベース

( grep)

文字列・配列による 表現はクロージャで表現する

callable

を採用していない による別名使用は極力しない

PSR-4 (use )

Page 6

2540

と静的解析

pixiv

たぶん 年頃 デプロイ時に必ず でのチェックを実施

( 2014 ) php -l

それ以前は を含むファイルをデプロイすることがまれにあった

SyntaxError

年 月正規表現ベースの を導入

2016 3 : lint

の 単位で される度に実行・コメント

GitLab MR push

年頃から 検証 静的解析がもたらす大 型検査時代

● →

2016 Phan Phan PHP

(phpcon2016)

年 月 を本格的に に導入

2018 6 : PHPStan CI

Page 7

2540

に寄らない利点

OOP

この利点は と による静的解析によっておよそ無効化された。よって

PhpStorm PHPStan
軽々に他者に推奨する戦略ではない。

インスタンス化 メソッド呼び出しの過程を経ると、 などの

● →

grep/sed/awk

プリミティブなテキスト編集ツールだけではメソッド利用箇所の洗い出しやリファクタリング の妨げとなる。この状況は既に大量のコードがあるプロジェクトを効率よくメンテする側面
においては大変に痛かった。

繰り返すが、現在においては型と静的解析の力を利用しながら のリファクタリ

PhpStorm

ング機能などを利用し、過不足にほかのツールを利用するの懸命だろう

Page 8

2540

正規表現ベースのチェッカー

(linter)

適用するパターン・除外するパターンを書ける

では との のあったファイルに対してチェッカーを適用

MR master diff

推奨されないバッドノウハウや表記揺れなどを抑止する目的

除外パターンも書けるので特定の場合のみ例外的に許可もしやすい

例 テストコードでのみ使用可

:

パターンのテストもあるのでチームメンバーが必要に応じて加除

Page 9

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],
],
],
],

Page 10

2540

Phan

コードを強力に静的解析する

連想配列の要素や特定のリテラルが来ること期待して解析できる

@phan-return array{mode:’foo’|’bar’,hoge:string}

明示しなくても実行パスを収集して最大限に型を推論してくれる

解析の度に全コードをスキャンするので大規模なコードベースでは、

とても時間がかかる

Page 11

2540

PHPStan

コードを強力に解析するが、静的情報だけではなく実行時情報を活用する

正確に検査するためには解析対象をオートロードあるいは事前読み込みできるようにす

( )

ることが前提

一回のプロセス起動で多数のファイルを同時に解析すると多量のメモリを消費するので、

と違ってプロジェクトの全クラスを一度に検査する用途は向かない

Phan

Page 12

2540

pixiv CI

および のテストによる動的解析と

PHPUnit( JS )

と正規表現ベースの による静的解析の二本立て

PHPStan linter

前述の通り、静的解析には ではなく を採用している

Phan PHPStan

実行環境の改善により、 の における のブ

CI GitLab Merge Request(GitHub Pull Request)
ランチに してから 秒前後で動的解析と静的解析の結果が得られる

push 60

Page 13

2540

と型

PHP

Page 14

2540

アプリケーションと型

PHP

そもそもが動的型付け言語で、静的に型を付ける上で不利な面も多い

時などは、

ATTR_EMULATE_PREPARES

$_GET $_POST PDO

, , ( )

あらゆる値を文字列型または再帰的に文字列を要素とする配列として扱う

( )

そのような値に対して「適切なキャスト」を書くのは「とても」難しい

不用意な判定で にキャストするのはバグや脆弱性の温床になる

string->int

の型宣言はデフォルトでキャストするので強いリスクがある

PHP7

が必須

declare(strict_types=1);
( )

Page 15

2540

型宣言への態度

既存の大規模なプロジェクトへの適用には強い懸念がある

特に のキャストが発生するケース

string->int

設定済みなら 処理系が、

declare(strict_types=1)

PHP

未設定なら人間が不用意にキャストしてしまうことがある

新規のプロジェクトでも、値を適切に扱える環境で慎重に導入したい

ではスカラー型宣言 は利用せず に留めたい

pixiv (int, string, bool) PHPDoc

Page 16

2540

ちょっと気になってるけど使ってない

https://github.com/sensiolabs-de/deptrac

https://github.com/vimeo/psalm