Upgrade to Pro — share decks privately, control downloads, hide ads and more …

レガシーシステムへのPHPStan導入から半年での課題と効果

don
February 09, 2024

 レガシーシステムへのPHPStan導入から半年での課題と効果

PHPerKaigi 2024 で発表した内容になります。

don

February 09, 2024
Tweet

More Decks by don

Other Decks in Programming

Transcript

  1. don (頓花) 出身:大阪府 年齢:29 歳 趣味:ゲーム, アニメ, マンガ, デバイス収集 etc...

    略歴 2019 年 株式会社ラクス入社 技術スタック PHP 歴: 5 年 #phperkaigi #c 自己紹介   ©RAKUS Co., Ltd. 2
  2. 楽楽販売 クラウド型の販売管理システム Web アプリケーション バックエンドはPHP /PostgreSQL 独自フレームワーク PHP5 の時代から 15

    年以上 続くソースコード 約35 万行(PHP コードのみで) #phperkaigi #c プロダクトの説明   ©RAKUS Co., Ltd. 3
  3. 導入していた静的解析ツール PhpStorm のInspection IDE 上で解析を実行 SonarQube 重複コードのチェックなど CI で解析を実行 SonarQube

    とは 多くのプログラミング言語をサポートしている静的解析ツール ※ https://docs.sonarsource.com/sonarqube/latest/ #phperkaigi #c 静的解析ツール   ©RAKUS Co., Ltd. 7
  4. PhpStorm のInspection の課題 既存コードと新規コードの指摘が判別つかない CI を設定するのが難しい ⇒ 解析は強力であるが、修正可否をチェックしづらい SonarQube の課題

    型のチェックなどの解析がない カスタムルールの追加が難しい ⇒ 言語に特化した静的解析が実施しづらい #phperkaigi #c 既存の静的解析ツールでの課題   ©RAKUS Co., Ltd. 9
  5. 新機能 型付きプロパティの導入 列挙型/交差型/never 型/true ・false ・null 型の追加 readonly アクセス修飾子/readonly クラスの導入

    非推奨 PHP 8.0 :非厳密な比較演算子の挙動変更 PHP 8.1 :ビルトイン関数の nullable でない引数に null を渡す PHP 8.2 :動的プロパティが非推奨 #phperkaigi #c 型定義の厳密化するPHP   ©RAKUS Co., Ltd. 14
  6. #phperkaigi #c PHPStan 導入:解析レベル Level 概要 0 基本的なチェック、未知のクラス、未知の関数、 $this 上で呼び出された未知のメソッド、それらのメソッドや関数に渡された引数の

    数が間違っている、常に未定義の変数をチェック 1 未定義の変数、 __call と __get を持つクラスの未知のマジックメソッドとプロパティがある可能性がある 2 ( $this だけでなく) すべての式で未知のメソッドをチェックし、PHPDocs を検証する 3 戻り値の型、プロパティに割り当てられた型の確認 4 基本的なデッドコードチェック( instanceof やその他の型チェックが常に false / 到達しない else 文/ return 後の到達不能コード) 5 メソッドや関数に渡される引数の型チェック 6 タイプヒントの欠落を報告する 7 部分的に間違っている論理和型の報告。論理和型の一部の型にしか存在しないメソッドを呼び出した場合、レベル7 はそのことを報告し 始めます( その他の不正確な状況も) 8 nullable 型に対するメソッド呼び出しとプロパティへのアクセスを報告する 9|max 混合型に厳密であること。この型で唯一許される操作は、この型を別の混合型に渡すことである   ©RAKUS Co., Ltd. 23
  7. 例)PHPStan でバグを発見 関数のオーバーライドの引数の型の不具合の発見 HogeMenuController.php:18:Method HogeMenuController::viewAction() overrides method AbstractMenuController::viewAction() but misses

    parameter #1 $form. 大規模リファクタリングを実施していたため、コードレビューから漏れていた。 PHPStan を導入していなければ、そのままリリースされていた可能性も... #phperkaigi #c 効果①:具体的な効果   ©RAKUS Co., Ltd. 35
  8. 例) $ ./vendor/bin/phpstan analyse --no-progress --memory-limit=2G --error-format=raw $(cat $CI_PROJECT_DIR/target.txt) Note:

    Using configuration file ./phpstan.neon. ... HogeCommand.php:25:Property HogeCommand::$requestParameter has no type specified. HogeCommand.php:704:Method HogeCommand::mailSend() has no return type specified. HogeCommand:704:Method HogeCommand::mailSend() has parameter $condition with no type specified. HogeCommand:704:Method AHogeCommand::mailSend() has parameter $aIsError with no type specified. HogeCommand:749:Offset 'user_name' might not exist on array|null. FileInfo.php:23:Class FileInfo has an uninitialized readonly property $fileId. Assign it in the constructor. FileInfo.php:24:Class FileInfo has an uninitialized readonly property $fileName. Assign it in the constructor. FileInfo.php:25:Class FileInfo has an uninitialized readonly property $filePath. Assign it in the constructor. FileInfo.php:25:Property FileInfo::$filePath is never read, only written. FileInfo.php:26:Class FileInfo has an uninitialized readonly property $fileOrder. Assign it in the constructor. FileInfo.php:26:Property FileInfo::$fileOrder is never read, only written. FileInfo.php:27:Class FileInfo has an uninitialized readonly property $fileType. Assign it in the constructor. ... #phperkaigi #c 課題と対応①:指摘の修正に時間がかかる   ©RAKUS Co., Ltd. 39
  9. 例)array を引数とする場合に正確な型指定 DB へのアクセスした値を配列で持ち回っているために指摘される 指摘に対応すると返値の配列を型も含めてすべて指定する必要がある → 除外ルールへ設定 既存処理の呼び出しで問題になるためすべて対応することは難しいと判断 /** *

    @return array{"foo": int, "bar": string} */ function fetchHoge(int $id): array { return $this->pdo->query("SELECT foo,bar FROM hoge WHERE id = $id")->fetch(); } #phperkaigi #c 課題と対応②:過剰な指摘が多数発生   ©RAKUS Co., Ltd. 41
  10. 課題 型定義がない PHPDoc の型定義が間違っている 対応 ボーイスカウトルールを設定 型定義を追加 PHPDoc で型定義を追加 ※

    基本は動作に影響のないようにPHPDoc の追加で対応 #phperkaigi #c 課題と対応③:既存コードの型定義不足   ©RAKUS Co., Ltd. 42