PHPStanでCustomRuleを作る / Make PHPStan CustomRule

PHPStanでCustomRuleを作る / Make PHPStan CustomRule

PHPカンファレンス福岡2019の発表資料です。
PHPStanのCustomRuleを使えば独自の静的検査をかけることが出来ます。具体例を通しながら、CustomRuleで何が実現できるのか、どうすれば自分たちで作れるようになるのかを解説しました。

B989cc865d53d8e26fdadac99727113c?s=128

Satoshi Kawashima

June 29, 2019
Tweet

Transcript

  1. © - BASE, Inc. PHPStanでCustomRuleを作る 川島 慧 / BASE株式会社 /

    / PHPカンファレンス福岡2019
  2. Product Division 川島 慧 @nazonohito

  3. © - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本

    • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次
  4. PHPStanとは?

  5. PHPStan - PHP Static Analysis Tool

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

  7. © - BASE, Inc. • 未定義変数の使⽤ • タイプヒントとの不⼀致 • 存在しないファンクション、メソッド、プロ

    パティの呼び出し • 無意味なコードの検出(未使⽤変数や絶対⼊ らない条件分岐) • etc 問題点の検出例
  8. 「PhpStormのインスペクションみたいな感じ?」

  9. はい、そうです。

  10. 「それ、PhpStormで良くね?」

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

  12. © - BASE, Inc. • 全員がPhpStormが使っているとは限らな い • PHPStanの⽅がCIで実⾏させやすい •

    検査(というか結果の判定)が厳密 • 検査項⽬が豊富 • 独⾃の検査(CustomRule)が作れる それ、PhpStormで良くね?
  13. © - BASE, Inc. PHPStanの⽅が検査項⽬が多い

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

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

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

  17. © - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本

    • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次
  18. 何故CustomRuleを作るのか? photos by USACE Afghanistan Engineer District-South https://www.flickr.com/photos/usace-tas/6898478368/

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

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

    \Aと\Zなんだよな
  21. \⾯倒くさい∕

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

    \Aと\Zなんだよな よくある指摘のコード化 CustomRule
  23. CustomRuleは もっと⾊々出来る

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

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

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

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

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

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

  30. 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

    チームの望むルールをコード化
  31. ソースコードの成⻑を 望む⽅向へ誘導する⼒ photos by NATS - UK air traffic control

    https://www.flickr.com/photos/natspressoffice/7562298996/
  32. でもごめんなさい

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

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

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

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

  37. © - BASE, Inc. • dependency-analyzerというクラスの 依存関係を解析するライブラリを作った 経験から、PHPStanの内部構造を直接 使った経験がある •

    内部構造の理解からCustomRule作成の ⼿ほどきをする 本⽇の私の⽴場
  38. © - BASE, Inc. この発表のゴール なにもわからない チョットデキル

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

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

  41. © - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本

    • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次
  42. © - BASE, Inc. • 1検査項⽬=1Ruleクラス PHPStanの検査はRuleクラスの集合

  43. © - BASE, Inc. よくあるPHPStanの実⾏例 $ vendor/bin/phpstan analyse -l -c

    phpstan.neon ./src -l オプションで検査レベルを指定する (レベルが上がるほど厳密になる)
  44. © - BASE, Inc. levelはRuleクラスのサブセットのエイリアス

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

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

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

    analyse -l -c phpstan.config.neon ./src PHPStanのconfigファイルを作る (拡張⼦は.neon) -c オプションに⾃分で作った configファイルを渡す
  48. © - BASE, Inc. • RuleクラスはPHPStan\Rules\Ruleイン ターフェースを実装しなければならない CustomRuleの追加の仕⽅

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

  50. © - BASE, Inc. . 字句解析する . 構⽂解析してASTを作る . ASTを解析する

    PHPStanの1ファイル辺りの解析処理の流れ
  51. © - BASE, Inc. • ソースコードをPHPにとっての最⼩の意 味単位まで分解する 1. 字句解析

  52. © - 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
  53. © - 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
  54. © - 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
  55. © - BASE, Inc. . ASTの解析 NodeScopeResolver ASTを再帰的に読み進める AST 解析

    Rule Rule Rule Rule Rule Rule ① ② ③ ⑤ ④
  56. © - 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
  57. © - BASE, Inc. . ASTの解析 NodeScopeResolver AST 解析 各Ruleにはどのノードを発⾒したときに

    検査メソッドを呼び出してほしいかが書いてある Rule Rule Rule Rule Rule Rule
  58. © - BASE, Inc. . ASTの解析 対象のノードを発⾒したとき、 そのRuleの検査メソッドを呼び出す 検査メソッドの呼び出し NodeScopeResolver

    AST 解析 Rule Rule Rule Rule Rule Rule
  59. © - BASE, Inc. 先程の実装例

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

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

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

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

  64. © - BASE, Inc. • PHPStanとは • 何故CustomRuleを作るのか • CustomRuleの基本

    • 望むCustomRuleを作るには • PHPStanのクラスを使いこなす • CustomRuleの具体例 ⽬次
  65. © - BASE, Inc. 少なすぎる引数 検査ロジックを書こうにも、 たった2つの引数しかない

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

  67. No

  68. Scope Node Broker Type RunLevelHelper TokenIterator ParameterAcceptorSelector FunctionParameterCheck PhpDocParser Lexer

    Container ClassCaseSensitivityCheck 望む解析を⾏うには PHPStanの機能群を 使いこなす必要がある
  69. 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

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

  71. © - BASE, Inc. • 主要3クラスの解説 • 具体例1: 新しく追加したメソッドには戻り 値型宣⾔を必須化する

    • DependencyInjectionの使い⽅ • 具体例2: 独⾃phpdocの作成 • PhpDocParserの使い⽅ この後のスライド
  72. © - BASE, Inc. 主要3クラス Scope Broker Node ※個⼈の主観で選んだものなので、公式情報ではありません

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

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

    3つの使い分け
  75. Node

  76. © - 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
  77. © - BASE, Inc. ソースコードとNodeとの対⽐ \PhpParser\Node\Stmt\Class_ \PhpParser\Node\Stmt\Property \PhpParser\Node\Stmt\ClassMethod \PhpParser\Node\Stmt\Namespace_

  78. © - BASE, Inc. • PhpParser\Nodeを基底とした複雑な継 承関係がある • 合計183個のクラス •

    解析したいコード近辺の情報はこいつを 辿りながら集めることになる PhpParser\Node
  79. © - BASE, Inc. • コードから理解しようとするのは⼤変な ので、ひたすらデバッグで中⾝を⾒なが ら使う • ⽚⽅向連結リストなので⼦要素へ解析を

    進める分は可能だが、親要素を辿ろうと するのは無理 Nodeを使いこなす
  80. Scope

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

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

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

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

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

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

  87. © - BASE, Inc. Scopeの作られ⽅ NodeScopeResolver AST 解析 スコープの切れ⽬となるノードを発⾒するたび、 Scopeオブジェクトを新しく作る

    Rule Rule Rule Rule Rule Rule Ruleクラスの検査メソッドを呼び出すときには、 そのノードが属するScopeオブジェクトもセットで渡す 検査メソッドの呼び出し Scope Scope Scope Scope
  88. © - BASE, Inc. 第2引数に⼊ってくる ここにScopeオブジェクトが⼊ってくる

  89. © - BASE, Inc. • 解析対象のファイル内部に関わることな らだいたいScopeクラスに聞くことにな る • ファイル名、クラス情報を取得する

    • 現在のNodeのスコープ上の位置を聞く • 変数スコープの型解決(重要) Scopeクラスを使いこなす
  90. © - BASE, Inc. ファイルについて聞く

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

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

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

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

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

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

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

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

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

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

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

  102. Broker

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

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

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

  106. © - BASE, Inc. リフレクションを提供するクラス Broker autoloader \PHPStan\Reflection\ClassReflection \ReflectionClass config.neon

    Rule クラス定義 動的プロパティ‧メソッドの 定義情報 組み込みリフレクションをラップした、 動的プロパティ‧メソッド定義も含めた リフレクションの提供
  107. © - BASE, Inc. • Broker: 仲買⼈、周旋屋販売⼈ • 解析対象のファイル以外からの(主にクラスや関数 の)リフレクションを供給する

    • PHPStanは動的メソッド‧プロパティも解析できる ようにサポートするための機能があり、それらを踏ま えた上での独⾃のリフレクションクラスを⽣成する • ⾃分でReflectionを取ろうとせずBrokerに委託する のがおそらく正しいPHPStanスタイル PHPStan\Broker\Broker
  108. © - BASE, Inc. • 「今後新しく追加するメソッドには必ず 戻り値型宣⾔を書いてね」というルール • gitと連携することで、どれが新しく追 加されたものなのかを調べることが出来

    る 具体例1:新しく追加されたメソッドの検査
  109. © - BASE, Inc. 作ったコード(要点部分のみ)

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

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

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

  113. © - BASE, Inc. 1. 修正前後のファイルコンテンツを⼊⼿ HEAD a fd da

    ec e fc f b faefdc a f b master feature_branch
  114. © - 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
  115. © - 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 <?php declare(strict_types= );
  116. © - 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 <?php declare(strict_types= );
  117. © - BASE, Inc. . ASTの⼊⼿ ClassMethod ClassMethod ClassMethod ClassMethod

    ClassMethod PHP-Parserを使ってASTの取得 マージベース時点のファイルコンテンツ 現時点のファイルコンテンツ
  118. © - BASE, Inc. 3. 追加されたClassMethodを検出 ASTからClassMethodノードをすべて拾い出して差分を求めるだけ ClassMethod ClassMethod ClassMethod

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

  120. © - BASE, Inc. • LaravelのようなDI (DependencyInjection)が出来る • コンストラクタにタイプヒントを書く とそのオブジェクトが注⼊される

    • nette/diというDIコンテナライブラリで 実現されている DIを使いこなす
  121. © - BASE, Inc. 1. まずは注⼊したいクラスを⽤意する

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

  123. © - BASE, Inc. 3. 実⾏時にneonファイルを渡す $ vendor/bin/phpstan analyze -c

    ./conf/phpstan.config.neon src/ -cオプションに渡す
  124. © - BASE, Inc. 4. コンストラクタにタイプヒントを書く

  125. © - BASE, Inc. • Gitと連携させればコードの変化を捉え た検査が実現できる • 変化を捉えるにはPHP-Parserが便利 •

    DIコンテナを利⽤すればNode, Scope以 外のクラスが何でも⼿に⼊る まとめ
  126. © - BASE, Inc. • traitをuseするのに必要なプロパティを 独⾃タグで⽰す • traitが持つ暗黙的依存を表現し、検査 する

    • class側でうっかり暗黙的依存を破って しまう事故を防⽌する 具体例2:traitの暗黙的依存を⽰す
  127. © - BASE, Inc. やりたいこと:traitに付加情報として必要なプロパティ 名を記述する このtraitをuseするclassには valueプロパティが必要 classにvalueプロパティが 必要であることを⽰す独⾃タグ

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

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

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

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

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

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

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

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

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

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

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

    まとめ
  139. © - BASE, Inc. • PSR- は個別のアプリケーション向けの独⾃タグ を考慮していて、以下の規約が定められている • タグの先頭にPHPスタイルの名前空間をつける

    • 例:@\Doctrine\Orm\Mapping\Entity() • タグの先頭にハイフンを付けたベンダ名をつける • 例:@phan-closure-scope 余談:PSR- における独⾃タグの規約
  140. ご清聴ありがとうございました