Slide 1

Slide 1 text

© - BASE, Inc. PHPStanでCustomRuleを作る 川島 慧 / BASE株式会社 / / PHPカンファレンス福岡2019

Slide 2

Slide 2 text

Product Division 川島 慧 @nazonohito

Slide 3

Slide 3 text

© - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本 • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次

Slide 4

Slide 4 text

PHPStanとは?

Slide 5

Slide 5 text

PHPStan - PHP Static Analysis Tool

Slide 6

Slide 6 text

コードの問題点を発⾒する 静的解析ツール

Slide 7

Slide 7 text

© - BASE, Inc. • 未定義変数の使⽤ • タイプヒントとの不⼀致 • 存在しないファンクション、メソッド、プロ パティの呼び出し • 無意味なコードの検出(未使⽤変数や絶対⼊ らない条件分岐) • etc 問題点の検出例

Slide 8

Slide 8 text

「PhpStormのインスペクションみたいな感じ?」

Slide 9

Slide 9 text

はい、そうです。

Slide 10

Slide 10 text

「それ、PhpStormで良くね?」

Slide 11

Slide 11 text

ぶっちゃけ検査内容は だいぶ被ってる

Slide 12

Slide 12 text

© - BASE, Inc. • 全員がPhpStormが使っているとは限らな い • PHPStanの⽅がCIで実⾏させやすい • 検査(というか結果の判定)が厳密 • 検査項⽬が豊富 • 独⾃の検査(CustomRule)が作れる それ、PhpStormで良くね?

Slide 13

Slide 13 text

© - BASE, Inc. PHPStanの⽅が検査項⽬が多い

Slide 14

Slide 14 text

© - BASE, Inc. PHPStanの⽅が検査項⽬が多い

Slide 15

Slide 15 text

© - BASE, Inc. 詳細はこちらへ https://speakerdeck.com/hirak/php-static-analysis

Slide 16

Slide 16 text

Phanとの⽐較の話はしません"

Slide 17

Slide 17 text

© - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本 • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次

Slide 18

Slide 18 text

何故CustomRuleを作るのか? photos by USACE Afghanistan Engineer District-South https://www.flickr.com/photos/usace-tas/6898478368/

Slide 19

Slide 19 text

僕らはたくさん コードレビューしなければならない

Slide 20

Slide 20 text

© - BASE, Inc. よく指摘するレビュー項⽬がある このクラスの中で こいつに触ってほしくないな array_pushは 遅いんだよな 正規表現は^や$よりも \Aと\Zなんだよな

Slide 21

Slide 21 text

\⾯倒くさい∕

Slide 22

Slide 22 text

© - BASE, Inc. よく指摘するレビュー項⽬がある このクラスの中で こいつに触ってほしくないな array_pushは 遅いんだよな 正規表現は^や$よりも \Aと\Zなんだよな よくある指摘のコード化 CustomRule

Slide 23

Slide 23 text

CustomRuleは もっと⾊々出来る

Slide 24

Slide 24 text

© - BASE, Inc. • gitと連携させるとコードの変化を捉え た検査をすることが出来る 他のツールとの連携 +

Slide 25

Slide 25 text

© - BASE, Inc. • 独⾃のphpdoc tagで作り、それを元に した検査ができる 独⾃phpdoc tagが作れる

Slide 26

Slide 26 text

© - BASE, Inc. CustomRuleで出来ること 新規コードに限定した検査 頻出するレビュー指摘の⾃動化 シンタックスの補強

Slide 27

Slide 27 text

プロダクトコードは ⽇々成⻑し続ける

Slide 28

Slide 28 text

秩序なく成⻑するコード photos by Luca Pedroni https://www.flickr.com/photos/sportpixonline/14005708634/

Slide 29

Slide 29 text

向かいたい理想はあっても 道のりが遠い…

Slide 30

Slide 30 text

photos by Peter Guilliatt https://www.flickr.com/photos/pguilliatt/5980554361/in/photolist-a7tUse-81JAH3- DKKX98-2bqJH7c-276ZXxc-2vy68A-9mH7aK-cy4Ppb-4Kq4Bj-2a1dGg6-a2nGLT-cwfK51-dY5udY- odfhX6-62m3xh-nyRmq3-jkAA4v-oy6hcc-4z5Bhr-6votG8-7k9h6N-hTGmLR-8fD8Lk-myEcPM- byDsU-9k24Td-q4tW8F-neABxW-oeGejq-dLBq8D-eX3EG2-7wQakY-aUZyCK-4z9Nv5-2qMVM9- qqVDK9-pueLQ6-cwfNvE-XvAj6k-fKwfm4-aXr9yn-SUJ34u-cwfL2s-ptkKUN-RAoj71- esVYp8-8nTxAF-jwzhXx-28CFYXU-9k23K3 チームの望むルールをコード化

Slide 31

Slide 31 text

ソースコードの成⻑を 望む⽅向へ誘導する⼒ photos by NATS - UK air traffic control https://www.flickr.com/photos/natspressoffice/7562298996/

Slide 32

Slide 32 text

でもごめんなさい

Slide 33

Slide 33 text

まだプロダクトで 実践できてないんです

Slide 34

Slide 34 text

photos by @@@ https://hoge.dom/ IUUQTQBDLBHJTUPSHQBDLBHFTOB[POPIJUPEFQFOEFODZBOBMZ[FS EFQFOEFODZBOBMZ[FS

Slide 35

Slide 35 text

クラスの依存関係を 解析するライブラリ

Slide 36

Slide 36 text

© - BASE, Inc. 詳細はコチラ https://speakerdeck.com/nazonohito /analyze-php-dependencies

Slide 37

Slide 37 text

© - BASE, Inc. • dependency-analyzerというクラスの 依存関係を解析するライブラリを作った 経験から、PHPStanの内部構造を直接 使った経験がある • 内部構造の理解からCustomRule作成の ⼿ほどきをする 本⽇の私の⽴場

Slide 38

Slide 38 text

© - BASE, Inc. この発表のゴール なにもわからない チョットデキル

Slide 39

Slide 39 text

微粒⼦レベルで何か分かったら 「PHPStan完全に理解した」 とツイートしてくださいね #phpconfuk #hall_fu

Slide 40

Slide 40 text

君だけの 最強のCustomRuleを作りだせ!! photos by Damian Avila https://www.flickr.com/photos/79069100@N03/24133051256/

Slide 41

Slide 41 text

© - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本 • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次

Slide 42

Slide 42 text

© - BASE, Inc. • 1検査項⽬=1Ruleクラス PHPStanの検査はRuleクラスの集合

Slide 43

Slide 43 text

© - BASE, Inc. よくあるPHPStanの実⾏例 $ vendor/bin/phpstan analyse -l -c phpstan.neon ./src -l オプションで検査レベルを指定する (レベルが上がるほど厳密になる)

Slide 44

Slide 44 text

© - BASE, Inc. levelはRuleクラスのサブセットのエイリアス

Slide 45

Slide 45 text

© - BASE, Inc. • CustomRuleクラスを作って、configに 追加するだけ CustomRuleの追加の仕⽅ $ vendor/bin/phpstan analyse -l -c phpstan.config.neon ./src

Slide 46

Slide 46 text

© - BASE, Inc. • CustomRuleクラスを作って、configに 追加するだけ CustomRuleの追加の仕⽅ $ vendor/bin/phpstan analyse -l -c phpstan.config.neon ./src PHPStanのconfigファイルを作る (拡張⼦は.neon)

Slide 47

Slide 47 text

© - BASE, Inc. • CustomRuleクラスを作って、configに 追加するだけ CustomRuleの追加の仕⽅ $ vendor/bin/phpstan analyse -l -c phpstan.config.neon ./src PHPStanのconfigファイルを作る (拡張⼦は.neon) -c オプションに⾃分で作った configファイルを渡す

Slide 48

Slide 48 text

© - BASE, Inc. • RuleクラスはPHPStan\Rules\Ruleイン ターフェースを実装しなければならない CustomRuleの追加の仕⽅

Slide 49

Slide 49 text

© - BASE, Inc. 実装例 さて、何をするルールでしょうか?

Slide 50

Slide 50 text

© - BASE, Inc. . 字句解析する . 構⽂解析してASTを作る . ASTを解析する PHPStanの1ファイル辺りの解析処理の流れ

Slide 51

Slide 51 text

© - BASE, Inc. • ソースコードをPHPにとっての最⼩の意 味単位まで分解する 1. 字句解析

Slide 52

Slide 52 text

© - BASE, Inc. • ソースコードをPHPにとっての最⼩の意 味単位まで分解する 1. 字句解析 T_OPEN_TAG T_NAMESPACE T_STRING T_CLASS T_STRING T_PRIVATE T_VARIABLE T_PUBLIC T_FUNCTION T_STRING T_STRING T_VARIABLE T_STRIN T_RETURN T

Slide 53

Slide 53 text

© - BASE, Inc. • nikic/PHP-Parserで構⽂解析し、 AST(abstract syntax tree)を⽣成する 2. 構⽂解析 T_OPEN_TAG T_NAMESPACE T_STRING T_CLASS T_STRING T_PRIVATE T_VARIABLE T_PUBLIC T_FUNCTION T_STRING T_STRING T_VARIABLE T_STRIN T_RETURN T Namespace statement Class statement Property statement ClassMethod statement

Slide 54

Slide 54 text

© - BASE, Inc. 2. 構⽂解析 \PhpParser\Node\Stmt\Namespace_ \PhpParser\Node\Stmt\Return_ \PhpParser\Node\Stmt\Expression \PhpParser\Node\Stmt\ClassMethod \PhpParser\Node\Stmt\Property \PhpParser\Node\Stmt\Class_ \PhpParser\Node\Stmt\PropertyProperty \PhpParser\Node\VarLinkIdentifier \PhpParser\Node\Scalar\Identifier \PhpParser\Node\Expr\Assign \PhpParser\Node\Expr\Variable \PhpParser\Node\Scalar\String \PhpParser\Node\Expr\BinaryOp\ConCat \PhpParser\Node\Expr\Variable \PhpParser\Node\Expr\Variable

Slide 55

Slide 55 text

© - BASE, Inc. . ASTの解析 NodeScopeResolver ASTを再帰的に読み進める AST 解析 Rule Rule Rule Rule Rule Rule ① ② ③ ⑤ ④

Slide 56

Slide 56 text

© - BASE, Inc. ノード=ASTの各頂点 \PhpParser\Node\Stmt\Namespace_ \PhpParser\Node\Stmt\Return_ \PhpParser\Node\Stmt\Expression \PhpParser\Node\Stmt\ClassMethod \PhpParser\Node\Stmt\Property \PhpParser\Node\Stmt\Class_ \PhpParser\Node\Stmt\PropertyProperty \PhpParser\Node\VarLinkIdentifier \PhpParser\Node\Scalar\Identifier \PhpParser\Node\Expr\Assign \PhpParser\Node\Expr\Variable \PhpParser\Node\Scalar\String \PhpParser\Node\Expr\BinaryOp\ConCat \PhpParser\Node\Expr\Variable \PhpParser\Node\Expr\Variable

Slide 57

Slide 57 text

© - BASE, Inc. . ASTの解析 NodeScopeResolver AST 解析 各Ruleにはどのノードを発⾒したときに 検査メソッドを呼び出してほしいかが書いてある Rule Rule Rule Rule Rule Rule

Slide 58

Slide 58 text

© - BASE, Inc. . ASTの解析 対象のノードを発⾒したとき、 そのRuleの検査メソッドを呼び出す 検査メソッドの呼び出し NodeScopeResolver AST 解析 Rule Rule Rule Rule Rule Rule

Slide 59

Slide 59 text

© - BASE, Inc. 先程の実装例

Slide 60

Slide 60 text

© - BASE, Inc. 先程の実装例 Class_ノード(クラス定義をしているNode) 発⾒時にprocessNode()が呼び出される NodeScopeResolverから 呼び出されたとき、$nodeに 解析対象のClass_ノードが⼊っている

Slide 61

Slide 61 text

© - BASE, Inc. 先程の実装例 Class_ノードで定義しているクラスが Tests\TestCaseクラスをextendsしているか確認 Class_ノードの属する名前空間が Tests\Unit配下であるか確認

Slide 62

Slide 62 text

© - BASE, Inc. 先程の実装例 LaravelでテストクラスがTests\TestCaseを ちゃんと継承しているか確認するルール

Slide 63

Slide 63 text

© - BASE, Inc. 結果 LaravelのTestCaseクラスでなくて、 PHPUnitのTestCaseクラスを継承してしまっている 今回はLaravelの例だが、他にも特定の名前空間配下は特定のクラスの継承を 強制するシーンは多いので、それらのケースにも応⽤できる

Slide 64

Slide 64 text

© - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本 • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次

Slide 65

Slide 65 text

© - BASE, Inc. 少なすぎる引数 検査ロジックを書こうにも、 たった2つの引数しかない

Slide 66

Slide 66 text

たった2つの引数で あらゆる検査を実現できるか?

Slide 67

Slide 67 text

No

Slide 68

Slide 68 text

Scope Node Broker Type RunLevelHelper TokenIterator ParameterAcceptorSelector FunctionParameterCheck PhpDocParser Lexer Container ClassCaseSensitivityCheck 望む解析を⾏うには PHPStanの機能群を 使いこなす必要がある

Slide 69

Slide 69 text

CustomRule作りには PHPStanの内部機能の使いこなし術が必要 photos by T4LLBERG https://www.flickr.com/photos/t4llberg/5828882565/in/photolist-9T5xHg-8Teu7k-5PT2gy- mUQ2C-6c1hJ2-9TaNjW-8ddebg-8dguGA-jYGzr-E8Npe-E8Npo-E8Npb-771rcz-7eLZbR-6uYodM- pfUY2z-8fPrxy-9E9LPF-5G4Xzg-pmfSN3-8fPrCU-8fLc2k-bt8mCy-qYw9hu-faSPbc-r3tRF-8S2n9x- BFC9jQ-48hG3o-5xZswi-5xZswn-5G9eJ9-pQBxd-pQBH6-8HSbd4-4aTS6-RLZ69o- sKZh8s-8fKT2x-5KTBaA

Slide 70

Slide 70 text

© - BASE, Inc. ほぼ説明のないREADME CustomRule作りのヒントを得るには既存のRuleを⾒てね!

Slide 71

Slide 71 text

© - BASE, Inc. • 主要3クラスの解説 • 具体例1: 新しく追加したメソッドには戻り 値型宣⾔を必須化する • DependencyInjectionの使い⽅ • 具体例2: 独⾃phpdocの作成 • PhpDocParserの使い⽅ この後のスライド

Slide 72

Slide 72 text

© - BASE, Inc. 主要3クラス Scope Broker Node ※個⼈の主観で選んだものなので、公式情報ではありません

Slide 73

Slide 73 text

何かしらの情報を取得する 主要クラス

Slide 74

Slide 74 text

© - BASE, Inc. • 解析対象のノード近辺の情報:Nodeに聞く • 解析対象のファイル内部の情報:Scopeに聞く • 解析対象のファイル以外の情報:Brokerに聞く 3つの使い分け

Slide 75

Slide 75 text

Node

Slide 76

Slide 76 text

© - BASE, Inc. ASTの頂点を表すクラス コレ \PhpParser\Node\Stmt\Namespace_ \PhpParser\Node\Stmt\Return_ \PhpParser\Node\Stmt\Expression \PhpParser\Node\Stmt\ClassMethod \PhpParser\Node\Stmt\Property \PhpParser\Node\Stmt\Class_ \PhpParser\Node\Stmt\PropertyProperty \PhpParser\Node\VarLinkIdentifier \PhpParser\Node\Scalar\Identifier \PhpParser\Node\Expr\Assign \PhpParser\Node\Expr\Variable \PhpParser\Node\Scalar\String \PhpParser\Node\Expr\BinaryOp\ConCat \PhpParser\Node\Expr\Variable \PhpParser\Node\Expr\Variable

Slide 77

Slide 77 text

© - BASE, Inc. ソースコードとNodeとの対⽐ \PhpParser\Node\Stmt\Class_ \PhpParser\Node\Stmt\Property \PhpParser\Node\Stmt\ClassMethod \PhpParser\Node\Stmt\Namespace_

Slide 78

Slide 78 text

© - BASE, Inc. • PhpParser\Nodeを基底とした複雑な継 承関係がある • 合計183個のクラス • 解析したいコード近辺の情報はこいつを 辿りながら集めることになる PhpParser\Node

Slide 79

Slide 79 text

© - BASE, Inc. • コードから理解しようとするのは⼤変な ので、ひたすらデバッグで中⾝を⾒なが ら使う • ⽚⽅向連結リストなので⼦要素へ解析を 進める分は可能だが、親要素を辿ろうと するのは無理 Nodeを使いこなす

Slide 80

Slide 80 text

Scope

Slide 81

Slide 81 text

⾊々な「スコープ」を扱うクラス

Slide 82

Slide 82 text

© - BASE, Inc. 例えばこのコードの場合

Slide 83

Slide 83 text

© - BASE, Inc. 例えばこのコードの場合 名前空間定義スコープ

Slide 84

Slide 84 text

© - BASE, Inc. 例えばこのコードの場合 名前空間定義スコープ クラス定義スコープ

Slide 85

Slide 85 text

© - BASE, Inc. 例えばこのコードの場合 名前空間定義スコープ クラス定義スコープ プロパティ定義スコープ メソッド定義スコープ

Slide 86

Slide 86 text

© - BASE, Inc. 例えばこのコードの場合 名前空間定義スコープ クラス定義スコープ プロパティ定義スコープ メソッド定義スコープ 無名関数定義スコープ

Slide 87

Slide 87 text

© - BASE, Inc. Scopeの作られ⽅ NodeScopeResolver AST 解析 スコープの切れ⽬となるノードを発⾒するたび、 Scopeオブジェクトを新しく作る Rule Rule Rule Rule Rule Rule Ruleクラスの検査メソッドを呼び出すときには、 そのノードが属するScopeオブジェクトもセットで渡す 検査メソッドの呼び出し Scope Scope Scope Scope

Slide 88

Slide 88 text

© - BASE, Inc. 第2引数に⼊ってくる ここにScopeオブジェクトが⼊ってくる

Slide 89

Slide 89 text

© - BASE, Inc. • 解析対象のファイル内部に関わることな らだいたいScopeクラスに聞くことにな る • ファイル名、クラス情報を取得する • 現在のNodeのスコープ上の位置を聞く • 変数スコープの型解決(重要) Scopeクラスを使いこなす

Slide 90

Slide 90 text

© - BASE, Inc. ファイルについて聞く

Slide 91

Slide 91 text

© - BASE, Inc. 今どのスコープにいるのか聞く $scope->getNamespace(); // null $scope->isInFirstLevelStatement(); // true $scope->isInClass(); // false $scope->isInAnonymousFunction(); // false

Slide 92

Slide 92 text

© - BASE, Inc. 今どのスコープにいるのか聞く $scope->getNamespace(); // ʻSandbox\PHPStan\Target’ $scope->isInFirstLevelStatement(); // true $scope->isInClass(); // false $scope->isInAnonymousFunction(); // false

Slide 93

Slide 93 text

© - BASE, Inc. 今どのスコープにいるのか聞く $scope->getNamespace(); //ʻSandbox\PHPStan\Target’ $scope->isInFirstLevelStatement(); // true $scope->isInClass(); // true $scope->isInAnonymousFunction(); // false

Slide 94

Slide 94 text

© - BASE, Inc. 今どのスコープにいるのか聞く $scope->getNamespace(); //ʻSandbox\PHPStan\Target’ $scope->isInFirstLevelStatement(); // false $scope->isInClass(); // true $scope->isInAnonymousFunction(); // true

Slide 95

Slide 95 text

© - BASE, Inc. 変数の中⾝や、式の結果を聞く $scope->getType($node); // ConstantStringType(value='string') String型であり、値も分かっている状態

Slide 96

Slide 96 text

© - BASE, Inc. 変数の中⾝や、式の結果を聞く $scope->getType($node); // ConstantStringType(value=ʻstringstring') String型であり、値も分かっている状態

Slide 97

Slide 97 text

© - BASE, Inc. 変数の中⾝や、式の結果を聞く $scope->getType($node); // ConstantStringType(value=ʻstringstringstringstring') String型であり、値も分かっている状態

Slide 98

Slide 98 text

© - BASE, Inc. 変数の中⾝や、式の結果を聞く $scope->getType($node); // StringType String型だと分かっているが、 値は分からない

Slide 99

Slide 99 text

© - BASE, Inc. 変数の中⾝や、式の結果を聞く $scope->getType($node); // StringType String型だと分かっているが、値は分からない

Slide 100

Slide 100 text

© - BASE, Inc. 変数の中⾝や、式の結果を聞く $scope->getType($node); // StringType String型だと分かっているが、値は分からない

Slide 101

Slide 101 text

© - BASE, Inc. 変数の中⾝や、式の結果を聞く $scope->getType($node); // MixedType どの型かも分からない

Slide 102

Slide 102 text

Broker

Slide 103

Slide 103 text

グローバルから (主に)クラスのリフレクションを⼊⼿するクラス

Slide 104

Slide 104 text

© - BASE, Inc. リフレクションのとり⽅

Slide 105

Slide 105 text

© - BASE, Inc. PHPStanは動的プロパティ‧メソッドも解析するための 機能がある

Slide 106

Slide 106 text

© - BASE, Inc. リフレクションを提供するクラス Broker autoloader \PHPStan\Reflection\ClassReflection \ReflectionClass config.neon Rule クラス定義 動的プロパティ‧メソッドの 定義情報 組み込みリフレクションをラップした、 動的プロパティ‧メソッド定義も含めた リフレクションの提供

Slide 107

Slide 107 text

© - BASE, Inc. • Broker: 仲買⼈、周旋屋販売⼈ • 解析対象のファイル以外からの(主にクラスや関数 の)リフレクションを供給する • PHPStanは動的メソッド‧プロパティも解析できる ようにサポートするための機能があり、それらを踏ま えた上での独⾃のリフレクションクラスを⽣成する • ⾃分でReflectionを取ろうとせずBrokerに委託する のがおそらく正しいPHPStanスタイル PHPStan\Broker\Broker

Slide 108

Slide 108 text

© - BASE, Inc. • 「今後新しく追加するメソッドには必ず 戻り値型宣⾔を書いてね」というルール • gitと連携することで、どれが新しく追 加されたものなのかを調べることが出来 る 具体例1:新しく追加されたメソッドの検査

Slide 109

Slide 109 text

© - BASE, Inc. 作ったコード(要点部分のみ)

Slide 110

Slide 110 text

© - BASE, Inc. 作ったコード(要点部分のみ) このブランチで修正されたファイルか確認

Slide 111

Slide 111 text

© - BASE, Inc. 作ったコード(要点部分のみ) このブランチで追加されたメソッドを取得

Slide 112

Slide 112 text

© - BASE, Inc. 作ったコード(要点部分のみ) 戻り値型宣⾔があるか確認 (getReturnTypeメソッド) なければエラー

Slide 113

Slide 113 text

© - BASE, Inc. 1. 修正前後のファイルコンテンツを⼊⼿ HEAD a fd da ec e fc f b faefdc a f b master feature_branch

Slide 114

Slide 114 text

© - BASE, Inc. 1. 修正前後のファイルコンテンツを⼊⼿ 1. マージベースのコミットハッシュの取得 $ git show-branch --merge-base master HEAD b faefdc b d c b b d f ab a fd da ec e fc f b faefdc a f b master feature_branch

Slide 115

Slide 115 text

© - BASE, Inc. 1. 修正前後のファイルコンテンツを⼊⼿ a fd da ec e fc f b faefdc a f b master feature_branch 2. 修正後のファイルコンテンツを取得 $ git show HEAD:src/Hoge.php

Slide 116

Slide 116 text

© - BASE, Inc. 1. 修正前後のファイルコンテンツを⼊⼿ a fd da ec e fc f b faefdc a f b master feature_branch 3. 修正前(マージベース)のファイルコンテンツを取得 $ git show fc f :src/Hoge.php

Slide 117

Slide 117 text

© - BASE, Inc. . ASTの⼊⼿ ClassMethod ClassMethod ClassMethod ClassMethod ClassMethod PHP-Parserを使ってASTの取得 マージベース時点のファイルコンテンツ 現時点のファイルコンテンツ

Slide 118

Slide 118 text

© - BASE, Inc. 3. 追加されたClassMethodを検出 ASTからClassMethodノードをすべて拾い出して差分を求めるだけ ClassMethod ClassMethod ClassMethod ClassMethod ClassMethod ClassMethod

Slide 119

Slide 119 text

© - BASE, Inc. PHPStanはDI出来る DependencyInjectionで 任意のクラスを取得できる!

Slide 120

Slide 120 text

© - BASE, Inc. • LaravelのようなDI (DependencyInjection)が出来る • コンストラクタにタイプヒントを書く とそのオブジェクトが注⼊される • nette/diというDIコンテナライブラリで 実現されている DIを使いこなす

Slide 121

Slide 121 text

© - BASE, Inc. 1. まずは注⼊したいクラスを⽤意する

Slide 122

Slide 122 text

© - BASE, Inc. . neonファイルに追加する

Slide 123

Slide 123 text

© - BASE, Inc. 3. 実⾏時にneonファイルを渡す $ vendor/bin/phpstan analyze -c ./conf/phpstan.config.neon src/ -cオプションに渡す

Slide 124

Slide 124 text

© - BASE, Inc. 4. コンストラクタにタイプヒントを書く

Slide 125

Slide 125 text

© - BASE, Inc. • Gitと連携させればコードの変化を捉え た検査が実現できる • 変化を捉えるにはPHP-Parserが便利 • DIコンテナを利⽤すればNode, Scope以 外のクラスが何でも⼿に⼊る まとめ

Slide 126

Slide 126 text

© - BASE, Inc. • traitをuseするのに必要なプロパティを 独⾃タグで⽰す • traitが持つ暗黙的依存を表現し、検査 する • class側でうっかり暗黙的依存を破って しまう事故を防⽌する 具体例2:traitの暗黙的依存を⽰す

Slide 127

Slide 127 text

© - BASE, Inc. やりたいこと:traitに付加情報として必要なプロパティ 名を記述する このtraitをuseするclassには valueプロパティが必要 classにvalueプロパティが 必要であることを⽰す独⾃タグ

Slide 128

Slide 128 text

© - BASE, Inc. 作ったコード

Slide 129

Slide 129 text

© - BASE, Inc. 作ったコード class内部の `use SomeTrait;` 部分を捕まえる

Slide 130

Slide 130 text

© - BASE, Inc. 作ったコード traitにかかれている 独⾃タグを集めている

Slide 131

Slide 131 text

© - BASE, Inc. 作ったコード 独⾃タグに書かれたプロパティが クラスにあるか確認

Slide 132

Slide 132 text

© - BASE, Inc. • phpstan/phpdoc-parserという別ライ ブラリが標準で読み込まれる • 名前の通りphpdocのparserで、 phpdocの解析ができるようになる PhpDocParserを使いこなす

Slide 133

Slide 133 text

© - BASE, Inc. PhpDocParserのBasicUsage DIでLexerとParserを⼊⼿ LexerでPHPDoc(string型)を字句解析 Parserで構⽂解析 getTagsByNameで 任意のタグの値を取得できる

Slide 134

Slide 134 text

© - BASE, Inc. . PHPDocを⽂字列で⼊⼿する

Slide 135

Slide 135 text

© - BASE, Inc. . PHPDocを⽂字列で⼊⼿する traitのリフレクションを Brokerから⼊⼿する リフレクションから PHPDocを⽂字列で⼊⼿できる

Slide 136

Slide 136 text

© - BASE, Inc. 2. 独⾃タグの値を取得する PhpDocParserで独⾃タグに 書かれた値を取得する

Slide 137

Slide 137 text

© - BASE, Inc. . traitをuseしているクラスにプロパティがあるか確認 解析対象のファイル内部なら Scopeからもリフレクションが取れる リフレクションから プロパティの有無を確認できる

Slide 138

Slide 138 text

© - BASE, Inc. • 独⾃タグを使えば、PHPのシンタックス で表現できないことも表現できる • PHPDocはphpstan/phpdoc-parserを 使えば簡単にパースできる まとめ

Slide 139

Slide 139 text

© - BASE, Inc. • PSR- は個別のアプリケーション向けの独⾃タグ を考慮していて、以下の規約が定められている • タグの先頭にPHPスタイルの名前空間をつける • 例:@\Doctrine\Orm\Mapping\Entity() • タグの先頭にハイフンを付けたベンダ名をつける • 例:@phan-closure-scope 余談:PSR- における独⾃タグの規約

Slide 140

Slide 140 text

ご清聴ありがとうございました