Slide 1

Slide 1 text

PHP における静的解析 (あるいはそもそも静的解析とは) 2024-01-11 PHPカンファレンス北海道2024 全然野菜

Slide 2

Slide 2 text

なにかがおかしいコード

Slide 3

Slide 3 text

Slide 4

Slide 4 text

実話です · 私が 1 年目のときに自分がつくったバグ · 実際には長いコードの一部であり、デバッグに半日かかった · エラーハンドリング等も不十分だったのもある · PHP 的には構文エラーではないので余計に気づきにくい · $empty という変数は定義可能であるため

Slide 5

Slide 5 text

PHP における静的解析 (あるいはそもそも静的解析とは) 2024-01-11 PHPカンファレンス北海道2024 全然野菜

Slide 6

Slide 6 text

「静的解析」とは プログラムを実行せずに行う解析のこと · 構文エラー検出 · コーディングスタイルチェック · 複雑性の検出 · 型のチェック · etc. ...... c.f.)動的解析:自動テスト、プロファイリング etc. ......

Slide 7

Slide 7 text

PHP の静的解析ツール例 · php -l コマンド · PHPMD · PHP_CodeSniffer(phpcs) · PHPStan · Psalm · Phan · (PhpStrom)

Slide 8

Slide 8 text

PHP の静的解析ツール例 · php -l コマンド · PHPMD · PHP_CodeSniffer(phpcs) · PHPStan ←本日取り上げるのはこちら · Psalm · Phan · (PhpStrom)

Slide 9

Slide 9 text

PHPStan https://phpstan.org/ ぞうさん かわいいね

Slide 10

Slide 10 text

PHPStan で検出できるもの(一例) · 構文エラー · 未定義の変数/定数/関数/クラス/メソッド · 間接的に typo を検出できる · 型の不整合 · エラーチェック漏れなど · 冗長なコード

Slide 11

Slide 11 text

Web ブラウザ上でおためしできます https://phpstan.org/try

Slide 12

Slide 12 text

Q. 何がおかしい?

Slide 13

Slide 13 text

A. 変数の typo

Slide 14

Slide 14 text

Slide 15

Slide 15 text

Slide 16

Slide 16 text

prepare('SELECT * FROM users WHERE id = ?;'); $statement->executeStatement([1]); https://phpstan.org/try Q. 何がおかしい?

Slide 17

Slide 17 text

prepare('SELECT * FROM users WHERE id = ?;'); $statement->executeStatement([1]); https://phpstan.org/try A. 存在しないメソッド

Slide 18

Slide 18 text

format('n'); } $now = new DateTime(); echo getMonth($now); https://phpstan.org/try Q. 何がおかしい?

Slide 19

Slide 19 text

format('n'); } $now = new DateTime(); echo getMonth($now); https://phpstan.org/try A. 戻り値の型の不整合

Slide 20

Slide 20 text

format('n'); } $now = new DateTime(); echo getMonth($now); https://phpstan.org/try A. 引数の型の不整合

Slide 21

Slide 21 text

備考)PHP の DateTime と DateTimeImmutable <> DateTimeInterface DateTime DateTimeImmutable 互換性はない

Slide 22

Slide 22 text

Slide 23

Slide 23 text

https://phpstan.org/try

Slide 24

Slide 24 text

余談)PHPDoc と組み合わせてより高度な型情報を扱える 今回は割愛 $age */ public int $age; } /** * @param non-empty-list $persons */ function findOldestPerson(array $persons): Person { $oldestPerson = $persons[0]; foreach ($persons as $person) { if ($person->age > $oldestPerson->age) { $oldestPerson = $person; } } return $oldestPerson; }

Slide 25

Slide 25 text

余談)PHPDoc と組み合わせてより高度な型情報を扱える 今回は割愛 $age */ public int $age; } /** * @param non-empty-list $persons */ function findOldestPerson(array $persons): Person { $oldestPerson = $persons[0]; foreach ($persons as $person) { if ($person->age > $oldestPerson->age) { $oldestPerson = $person; } } return $oldestPerson; }

Slide 26

Slide 26 text

さて https://speakerdeck.com/twada/growing-reliable-code-phperkaigi-2022?slide=10

Slide 27

Slide 27 text

さて https://speakerdeck.com/twada/growing-reliable-code-phperkaigi-2022?slide=10 静的解析を実施するのは だいたいこのタイミング(たぶん)

Slide 28

Slide 28 text

冒頭のコードを PHPStan にかけると

Slide 29

Slide 29 text

冒頭のコードを PHPStan にかけると https://phpstan.org/r/45d617bb-1bc1-4e2a-a1e9-24b8deeefff9

Slide 30

Slide 30 text

冒頭のコードを PHPStan にかけると https://phpstan.org/r/45d617bb-1bc1-4e2a-a1e9-24b8deeefff9

Slide 31

Slide 31 text

つまり https://speakerdeck.com/twada/growing-reliable-code-phperkaigi-2022?slide=10 静的解析ツールを使っていれば 不具合の発見のタイミングを早め傷を小さく収められた (また、ツールによって瞬時に発見できた)

Slide 32

Slide 32 text

まとめ · 静的解析ツールを使うとテストコードを書く以外の方法で 潜在的な不具合(うっかりミス等)を発見できる · ツールを使いこなして生産性をあげよう · (発展)PHP における型を意識した設計、実装の幅を広げてくれ る · あくまで外部ツールであり、PHP のランタイムそのものを安 全にしてくれるわけではないので注意