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

PHPのバージョンアップ時にも役立ったAST(2026年版)

 PHPのバージョンアップ時にも役立ったAST(2026年版)

2026-03-21 PHPerKaigi 2026 レギュラートーク資料
https://fortee.jp/phperkaigi-2026

Avatar for Atsushi Matsuo

Atsushi Matsuo

March 21, 2026
Tweet

More Decks by Atsushi Matsuo

Other Decks in Programming

Transcript

  1. PHPのバージョンアップ時にも役立ったAST(2026年版) トークの概要 はじめに • 勉強会で学んだことが実際の業務に役立った事例を紹介 • AST(抽象構文木、Abstract Syntax Treeの略)がPHP 8.1からPHP

    8.2に バージョンアップした際の作業の一部で役立った事例 • ASTのハッシュ値に差分がないことを確認することで大幅にテスト工数を削減 2
  2. PHPのバージョンアップ時にも役立ったAST(2026年版) 自己紹介 はじめに 松尾篤 • PHP使用歴:約21年 • PHPを使った開発歴は約18年 • 2023年4月にGaroon開発チームに加入

    • Garoonのセキュリティを維持するYukimiチームの紹介 https://blog.cybozu.io/entry/2023/10/04/101916 • 過去にコントリビュートしたことがあるPHP関連のOSS(抜粋) • PHP-Parser • Phan • phpDocumentor • PHP Debug Bar • Smarty • Windows版PHP用libxml2 5
  3. PHPのバージョンアップ時にも役立ったAST(2026年版) Garoon開発チームが過去のバージョンアップ時に直面した課題たち PHPのリリースサイクルとバージョンアップの必要性 • PHP 8.0:比較演算子の挙動変更 20年ものの巨大レガシープロダクトをPHP 8.0にアップデートした際の対策と得られた知見 by 赤間

    仁志 https://speakerdeck.com/akamah/20nian-mononoju-da-regasipurodakutowo-php-8-dot-0niatupudetositaji-nodui-ce-tode-raretazhi-jian • PHP 8.1:mb_detect_encoding()の仕様変更 Garoon開発チームではPHP8.1の仕様変更とどう向き合ってきたのか by 千葉 泰理(ぱくとま) https://speakerdeck.com/pakutoma/how-we-have-responded-to-the-php-8-dot-1-mbstring-specification-changes • PHP 8.2:動的プロパティの非推奨化 PHP 9 に備えよ - 動的プロパティ、どうすればいぃ? by 荒瀬 泰輔 https://speakerdeck.com/taisukearase/php-9-nibei-eyo-dong-de-puropatei-dousurebaii 10
  4. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.2で推奨されなくなる機能 PHPのバージョンアップ時に参照する移行ガイド • https://www.php.net/manual/ja/migration82.deprecated.php より • 動的なプロパティの利用 •

    部分的にしかサポートされていない callable • ”${var}” / “${expr}” 形式の、文字列への値の埋め込み • 'テキストエンコーディング' QPrint, Base64, Uuencode, HTML-ENTITIES • 内部メソッド SplFileInfo::_bad_state_ex() • utf8_encode() と utf8_decode() 13
  5. PHPのバージョンアップ時にも役立ったAST(2026年版) AST バージョンアップ時に挙動が変わらない根拠としてASTに着目 • Abstract Syntax Treeの略 • 抽象構文木 •

    ソースコードを解析した後の木構造 • ソースコードの解析や変換に活用できる 21 ソースコード AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR name: "var" expr: "Hello World!" 1: AST_ECHO expr: AST_ENCAPS_LIST 0: AST_VAR name: "var" <?php $var = "Hello World!"; echo "${var}"; AST
  6. PHPのバージョンアップ時にも役立ったAST(2026年版) 同じソースコードであればASTも同じになる バージョンアップ時に挙動が変わらない根拠としてASTに着目 24 ソースコード AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR

    name: "var" expr: "Hello World!" 1: AST_ECHO expr: AST_ENCAPS_LIST 0: AST_VAR name: "var" <?php $var = "Hello World!"; echo "${var}"; 410dfe506da6502f9f81b89710ad379159b644d63520de6eca79f8ed86b6ffc4 1回目 AST ハッシュ値(SHA-256)
  7. PHPのバージョンアップ時にも役立ったAST(2026年版) 同じソースコードであればASTも同じになる バージョンアップ時に挙動が変わらない根拠としてASTに着目 25 ソースコード AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR

    name: "var" expr: "Hello World!" 1: AST_ECHO expr: AST_ENCAPS_LIST 0: AST_VAR name: "var" <?php $var = "Hello World!"; echo "${var}"; 410dfe506da6502f9f81b89710ad379159b644d63520de6eca79f8ed86b6ffc4 1回目 AST ハッシュ値(SHA-256) ソースコード AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR name: "var" expr: "Hello World!" 1: AST_ECHO expr: AST_ENCAPS_LIST 0: AST_VAR name: "var" <?php $var = "Hello World!"; echo "${var}"; 2回目 AST
  8. PHPのバージョンアップ時にも役立ったAST(2026年版) "${var}"から"{$var}"に置き換えてもASTが変わらない バージョンアップ時に挙動が変わらない根拠としてASTに着目 26 ソースコード AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR

    name: "var" expr: "Hello World!" 1: AST_ECHO expr: AST_ENCAPS_LIST 0: AST_VAR name: "var" <?php $var = "Hello World!"; echo "${var}"; 410dfe506da6502f9f81b89710ad379159b644d63520de6eca79f8ed86b6ffc4 "${var}" AST ハッシュ値(SHA-256) ソースコード AST_STMT_LIST 0: AST_ASSIGN var: AST_VAR name: "var" expr: "Hello World!" 1: AST_ECHO expr: AST_ENCAPS_LIST 0: AST_VAR name: "var" <?php $var = "Hello World!"; echo "{$var}"; "{$var}"; AST
  9. PHPのバージョンアップ時にも役立ったAST(2026年版) php-astのインストール PHPでASTを取得およびそのハッシュ値を比較する方法 • https://github.com/nikic/php-ast?tab=readme-ov-file#installation を参照 • macOSやLinuxの場合 • 「pecl

    install ast」を実行してphp.iniに「extension=ast.so」を追加 • 今ならPIE(PHP Installer for Extensions)を使ってインストールする方法も • もしくはコンパイルしてからインストールする方法もある(phpize → ./configure → make → sudo make install) • Windowsの場合 • php-astのDLLファイルをダウンロードしてextディレクトリに配置してからphp.ini に「extension=php_ast.dll」を追加 31
  10. PHPのバージョンアップ時にも役立ったAST(2026年版) php-astを実行するPHPのバージョンを意識する ASTのハッシュ値を確認する際に留意する点 • "${var}"から"{$var}"への変更については • PHP 8.2でphp-astを使った場合 • 変更前のソースコードだとPHP

    8.1で出力したASTと変わった • 変更後のソースコードであればPHP 8.1で出力したASTと同じになった • PHP 8.1でphp-astを使った場合 • ソースコードの変更前後でASTは変わらなかった • 使っているPHPのバージョンを変えずにASTのハッシュ値が同じか確認可能だった 36
  11. PHPのバージョンアップ時にも役立ったAST(2026年版) どの場合に差分が発生するか検証する ASTのハッシュ値を確認する際に留意する点 37 PHP 8.1でphp-astを使用 PHP 8.2でphp-astを使用 変更前のソースコード 410dfe506da6502f9f81b89710a

    d379159b644d63520de6eca79f 8ed86b6ffc4 2c12d382a9c54af519fbb7391c8 5f0652236bd896e464a2a9ff055c e9fd26068 変更後のソースコード 410dfe506da6502f9f81b89710a d379159b644d63520de6eca79f 8ed86b6ffc4 410dfe506da6502f9f81b89710a d379159b644d63520de6eca79f 8ed86b6ffc4 <?php $var = "Hello World!"; echo "${var}"; <?php $var = "Hello World!"; echo "{$var}"; • PHP-Parserを使った場合にはPHP 8.1でもPHP 8.2でも今回対象としてい る範囲においてはASTは同じだった • php-astを使った場合には変更前のソースコードに対してPHP 8.2で実行 するとASTが変わった • 同じソースコードでも、使用するツールやPHPのバージョンが異なると ハッシュ値が一致しない場合がある PHPの各バージョンでphp-astを使用して出力したASTのハッシュ値
  12. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.1でphp-astを使っても例外的にハッシュ値が変わるケースがあった ASTのハッシュ値を確認する際に留意する点 39 ソースコード <?php declare(strict_types = 1);

    class HelloWorld { /** * "${var}" */ public function sayHello(): string { return "Hello World!"; } } 32e80262eee2882016b752815393917a2d79efda6cdfefb8f8a40e26d7122a75 "${var}" ハッシュ値 ソースコード <?php declare(strict_types = 1); class HelloWorld { /** * "{$var}" */ public function sayHello(): string { return "Hello World!"; } } f71118033b77fbe03e32eb2f971a463e17b938f2c1ce8b70d68872116331e06c "{$var}" ハッシュ値
  13. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.1でphp-astを使っても例外的にハッシュ値が変わるケースがあった ASTのハッシュ値を確認する際に留意する点 • コード本体ではなくコメントまで一括置換したケース • PHP CS FixerやRectorによる置換ではなく、テキストエディターやIDEを使っ

    て単に「${」を「{$」に一括置換した場合 • DocComment(/** */で括られるコメント)内にある"${var}"および "${expr}"形式で書かれている文字列を置換した場合はphp-astで取得した ASTのハッシュ値が変わる場合があった • DocComment内を置換しなかった場合にはASTのハッシュ値は同じだった • 最終的にDocComment内部での置き換えであれば挙動への影響はないと判断 40
  14. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.5で注目した非推奨項目 PHP 8.5にバージョンアップする際にASTを活用できるケース • PHP 8.5.x で推奨されなくなる機能 https://www.php.net/manual/ja/migration85.deprecated.php

    • 正規化されていない型名でのキャスト • “正規化されていない型名 (boolean), (integer), (double), (binary) でキャストす ることは、 推奨されなくなりました。 (bool), (int), (float), (string) をそれぞれ 使ってください。” • セミコロンでcase文を終了させる • “case文をコロンではなく、セミコロンで終了させることは、 推奨されなくなりま した。” 44
  15. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.5にバージョンアップする際にASTを活用できる変更内容 PHP 8.5にバージョンアップする際にASTを活用できるケース • PHP 8.2で非推奨になった「”${var}” / “${expr}”

    形式の、文字列への 値の埋め込み」と同様の扱いができる変更 • 正規化されていない型名でのキャスト • (boolean) → (bool) • (integer) → (int) • (double) → (float) • (binary) → (string) • セミコロンでcase文を終了させる • case文の末尾にある ;(セミコロン) → :(コロン) 45
  16. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.4とPHP 8.5でASTのハッシュ値を比較した結果 PHP 8.5にバージョンアップする際にASTを活用できるケース • 正規化されていない型名でのキャストを変更した場合 • PHP

    8.4でphp-astを使って取得したASTは、ソースコードの変更前後で変わ らなかった • PHP 8.5でphp-astを使って取得したASTも、ソースコードの変更前後で変わ らなかった • PHP 8.5でphp-astを使って取得したASTは、PHP 8.4でphp-astを使って取得 したASTと同じだった 46 PHP 8.4でphp-astを使用 PHP 8.5でphp-astを使用 変更前のソースコード 4693d072bbfa4fb1832507cd6bea61 83e79a5f1bf42bddd1f47df8b7e5b45 4b6 4693d072bbfa4fb1832507cd6bea61 83e79a5f1bf42bddd1f47df8b7e5b45 4b6 変更後のソースコード 4693d072bbfa4fb1832507cd6bea61 83e79a5f1bf42bddd1f47df8b7e5b45 4b6 4693d072bbfa4fb1832507cd6bea61 83e79a5f1bf42bddd1f47df8b7e5b45 4b6 PHPの各バージョンでphp-astを使用して出力したASTのハッシュ値
  17. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.4とPHP 8.5でASTのハッシュ値を比較した結果 PHP 8.5にバージョンアップする際にASTを活用できるケース • case文の末尾にある ;(セミコロン)を :(コロン)に変更した場合

    • PHP 8.4でphp-astを使って取得したASTは、ソースコードの変更前後で変わ らなかった • 変更後のソースコードに対してPHP 8.5でphp-astを使って取得したASTは、 PHP 8.4でphp-astを使って取得したASTと同じだった • 変更前のソースコードに対してPHP 8.5でphp-astを使って取得したASTは、 PHP 8.4でphp-astを使って取得したASTと変わった 47 PHP 8.4でphp-astを使用 PHP 8.5でphp-astを使用 変更前のソースコード 617f67046f0e38cb19be702c4946ab2 43b4ae61bdd445c1d8a51afe8cfe9 a0ae a21dbf9fc5817f2450305d12a59c150 861fe3d161db5c4ae9e0363560cca5 ee4 変更後のソースコード 617f67046f0e38cb19be702c4946ab2 43b4ae61bdd445c1d8a51afe8cfe9 a0ae 617f67046f0e38cb19be702c4946ab2 43b4ae61bdd445c1d8a51afe8cfe9 a0ae PHPの各バージョンでphp-astを使用して出力したASTのハッシュ値
  18. PHPのバージョンアップ時にも役立ったAST(2026年版) PHP 8.5でASTのハッシュ値を取得する際に留意する点 PHP 8.5にバージョンアップする際にASTを活用できるケース • php-astを使う際にはPHP 8.5に対応したphp-ast 1.1.3に更新する •

    php-astでパースする際に指定するASTバージョンも更新する • 変更前:parse_code($code, $version=100); • 変更後:parse_code($code, $version=120); • php-astのASTバージョンが異なると出力されるASTが変わる 48 https://github.com/nikic/php-ast/releases/tag/v1.1.3
  19. PHPのバージョンアップ時にも役立ったAST(2026年版) ASTを使った影響範囲の調査例 ASTを使った影響範囲調査の応用例 • ASTは挙動の比較だけでなく影響範囲の絞り込みにも応用可能 • 単純な文字列検索よりASTをパースする方が影響範囲を絞り込みやすい • セミコロンで終了しているcase文の検出 •

    単なる「;」の検索では関係ない箇所がたくさん見つかってしまう • 非推奨になった関数やデバッグ用に使用している関数の検出 • コメントのように実際に関数を呼び出していない箇所や、似た名前の関数および接 頭辞が異なる関数が見つかってしまう • PHP 8.0で挙動が変更された比較演算子が実行される可能性がある箇所の検出 • 単なる「==」の検索では実際には挙動が変わらない箇所が数多く見つかってしまう 50