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

What We Can Learn From OSS

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for inouehi inouehi
April 13, 2024

What We Can Learn From OSS

『OSSから学ぶ技術』

PHPカンファレンス小田原
2024-04-13 18:00〜 かま
https://phpcon-odawara.jp/

Avatar for inouehi

inouehi

April 13, 2024
Tweet

More Decks by inouehi

Other Decks in Programming

Transcript

  1. 20

  2. 42 PHP Parser $ ./vendor/bin/php-parse file.php -r --var-dump $argv[1] $argv[2]

    $argv[3] $argv[0] 配列という名のフリーダム
  3. operations、ファイル名、PHPのコード(テキスト)が入力される。 • 形式は様々 ◦ php-parse ◦ -d ◦ --dump ◦

    file.php ◦ "<?php code" • 複数入力されうるし入力されないこともある • 順不同 43 コマンドラインインタフェースが持つ複雑さとは
  4. 46 PHP Parser - parseArgs() function parseArgs($args) { // 略

    foreach ($args as $arg) { // 引数を評価(後述) } return [$operations, $files, $attributes]; } https://github.com/nikic/PHP-Parser/blob/46be4560c4cd4bab2b74882c0da39a4548a5cfbe/bin/php-parse
  5. 47 PHP Parser - parseArgs() function parseArgs($args) { // 略

    foreach ($args as $arg) { // 引数を評価(後述) } return [$operations, $files, $attributes]; } https://github.com/nikic/PHP-Parser/blob/46be4560c4cd4bab2b74882c0da39a4548a5cfbe/bin/php-parse
  6. 48 PHP Parser - parseArgs() function parseArgs($args) { // 略

    foreach ($args as $arg) { // 引数を評価(後述) } return [$operations, $files, $attributes]; } https://github.com/nikic/PHP-Parser/blob/46be4560c4cd4bab2b74882c0da39a4548a5cfbe/bin/php-parse
  7. 49 PHP Parser - parseArgs() switch ($arg) { case '--dump':

    case '-d': $operations[] = 'dump'; break; case '--with-column-info': case '-c'; $attributes['with-column-info'] = true; break; https://github.com/nikic/PHP-Parser/blob/46be4560c4cd4bab2b74882c0da39a4548a5cfbe/bin/php-parse
  8. 50 PHP Parser - parseArgs() default: if (preg_match('/^--version=(.*)$/', $arg, $matches))

    { $attributes['version'] = PhpParser\PhpVersion::fromString($matches[1]); } elseif ($arg[0] === '-' && \strlen($arg[0]) > 1) { showHelp("Invalid operation $arg."); } else { $files[] = $arg; } https://github.com/nikic/PHP-Parser/blob/46be4560c4cd4bab2b74882c0da39a4548a5cfbe/bin/php-parse
  9. 52 PHPStan - bin/phpstan $application = new \Symfony\Component\Console\Application( 'PHPStan -

    PHP Static Analysis Tool', ComposerHelper::getPhpStanVersion() ); // 略 $application->run();
  10. 56

  11. 59 PHPStan $preFileCallback = null; $postFileCallback = static function (int

    $step) use ($errorOutput): void { $errorOutput->getStyle()->progressAdvance($step); }; $errorOutput->getStyle()->progressStart($allAnalysedFilesCount); $errorOutput->getStyle()->progressAdvance($allAnalysedFilesCount - $filesCount); // 略 if (!$debug) { $errorOutput->getStyle()->progressFinish(); } https://github.com/phpstan/phpstan-src/blob/9bb4ef961960a1056060209b3ed7e09b93c06f36/src/Command/AnalyseApplication.php
  12. 60 PHPStan $preFileCallback = null; $postFileCallback = static function (int

    $step) use ($errorOutput): void { $errorOutput->getStyle()->progressAdvance($step); }; $errorOutput->getStyle()->progressStart($allAnalysedFilesCount); $errorOutput->getStyle()->progressAdvance($allAnalysedFilesCount - $filesCount); // 略 if (!$debug) { $errorOutput->getStyle()->progressFinish(); } https://github.com/phpstan/phpstan-src/blob/9bb4ef961960a1056060209b3ed7e09b93c06f36/src/Command/AnalyseApplication.php
  13. 65

  14. 69 autoloadが持つ複雑性とは 開発環境 . ├─ bin │ └─ my-cli └─

    vendor └─ autoload.php プロダクション環境 . └─ vendor ├─ autoload.php └─ repository-name └─ package-name └─ bin └─ my-cli __DIR__ . '/../vendor/autoload.php' __DIR__ . '/../../../autoload.php'
  15. 71 Rector public function includeDependencyOrRepositoryVendorAutoloadIfExists() : void { $this->loadIfExistsAndNotLoadedYet(__DIR__ .

    '/../vendor/autoload.php'); } public function autoloadProjectAutoloaderFile() : void { $this->loadIfExistsAndNotLoadedYet(__DIR__ . '/../../../autoload.php'); } public function autoloadRectorInstalledAsGlobalDependency() : void { $this->loadIfExistsAndNotLoadedYet('vendor/autoload.php'); } https://github.com/rectorphp/rector/blob/11b9220a05ee3c1bcaa75d76c8b5e5baa8d01484/bin/rector.php ※大部分を省略しています
  16. 75 getNodeTypes()の違い PHPStan public function getNodeType(): string { return ClassMethod::class;

    } Rector public function getNodeTypes(): array { return [ClassMethod::class]; }
  17. 76 getNodeTypes()の違い PHPStan[1] public function getNodeType(): string { return ClassMethod::class;

    } Rector[2] public function getNodeTypes(): array { return [ClassMethod::class]; } 1. https://github.com/phpstan/phpstan-src/blob/3d43198f80f47da6fee60fb3d86ae004eee41f13/src/Rules/Methods/MethodAttributesRule.php 2. https://github.com/rectorphp/rector/blob/0e57251e460fb68e7ad8e1fdd0467e9db6ca82c8/rules/Php80/Rector/ClassMethod/SetStateToStaticRector.php PHPStanは1つ、Rectorは複数のノードを指定できるが、この裏側にあるメカニズムに違いがある。 (詳細はリンク先のコードを辿るなどして下さいmm)
  18. 77 getNodeTypes()の違い超概要 • PHPStanはノード毎にルールを対応づける。 $rules[$rule->getNodeType()][] = $rule; • Rectorはトラバース中にノードをスキップする。 private

    function isMatchingNodeType(string $nodeClass) : bool { foreach ($this->getNodeTypes() as $nodeType) { if (\is_a($nodeClass, $nodeType, \true)) { return \true; } } return \false; }
  19. 78 トラバースって何?? 参考資料 • 『PHP Parserで学ぶPHP』[1] • 『PHP Parserで学ぶPHPと静的解析』[2] •

    『木を見て!森を見て!目で見てわかるAST(抽象構文木)』[3] 1. https://speakerdeck.com/inouehi/php-parserdexue-buphp 2. https://speakerdeck.com/inouehi/learning-php-and-static-analysis-with-php-parser 3. https://speakerdeck.com/inouehi/understanding-ast-by-looking
  20. 79 ところで トラーバスでノードを総当たりしつつも不要なノードはスキップするという機構が 個人的にはなるほどポイントでもありました。 public final function enterNode(\PhpParser\Node $node) {

    $nodeClass = \get_class($node); if (!$this->isMatchingNodeType($nodeClass)) { // スキップ return null; } // 略 $node = $this->refactor($node); // リファクタを実行
  21. 84 ビジターって何?? 参考資料 • 『PHP Parserで学ぶPHP』[1] • 『PHP Parserで学ぶPHPと静的解析』[2] •

    『木を見て!森を見て!目で見てわかるAST(抽象構文木)』[3] 1. https://speakerdeck.com/inouehi/php-parserdexue-buphp 2. https://speakerdeck.com/inouehi/learning-php-and-static-analysis-with-php-parser 3. https://speakerdeck.com/inouehi/understanding-ast-by-looking
  22. 85 PHP Parserのビジター ビジターはNodeVisitorを実装する。 ※メソッドを抜粋 interface NodeVisitor { public function

    beforeTraverse(array $nodes); public function enterNode(Node $node); public function leaveNode(Node $node); public function afterTraverse(array $nodes); }
  23. 87 PHP Parserのビジター - NodeVisitorAbstract abstract class NodeVisitorAbstract implements NodeVisitor

    { public function beforeTraverse(array $nodes) { return null; } public function enterNode(Node $node) { return null; } public function leaveNode(Node $node) { return null; } public function afterTraverse(array $nodes) { return null; } }
  24. 99 • OSSは、デザインパターンやイディオムの宝箱 • あるいは、理論、原則、基礎の実践的事例 • 同じコンセプトにも異なる実装がありえる • ただし、その実装が常に最適とは限らない •

    実践知に気づくには、ベースとなる教養を育むことも重要 • 目的があるととっつきやすく、目的外の収穫もある • 目的外の収穫≒セレンデピティ(偶然得られた幸運)を増やすには機会を増やすこと