🍣

OSSコントリビューションのための基礎知識:PHP-CS-Fixer×字句トークン

に公開

1. なぜ字句トークンを学ぶのか

PHP-CS-Fixer は、コードを文字列ではなく トークン列(Tokens) として扱う。
「字句トークン」とは、PHPのソースコードを「最小単位(キーワード・識別子・記号など)」に分解したもの。
Fixer はこの列を操作してコードを整形している。

理解の目的

  • PHP の構文解析の前段階を理解する
  • Fixer がどのようにコードを安全に書き換えているかをイメージできるようにする

2. 字句解析(Lexical Analysis)とは

字句解析(lexer)は、テキストをトークンの列に分割する処理。
例として echo $a + 1; を与えると、以下のように分かれる。

種類 内容 PHPトークン名
キーワード echo T_ECHO
変数 $a T_VARIABLE
演算子 + '+'
整数 1 T_LNUMBER
記号 ; ';'

PHPではこの処理を token_get_all() 関数が担う。

3. PHPでの字句トークンの扱い

token_get_all() は、PHPコード文字列を配列として返す。

$code = '<?php echo $a + 1;';
$tokens = token_get_all($code);

foreach ($tokens as $token) {
    if (is_array($token)) {
        echo token_name($token[0]) . ' => ' . $token[1] . PHP_EOL;
    } else {
        echo $token . PHP_EOL; // 記号など
    }
}

出力例

T_OPEN_TAG => <?php 
T_ECHO => echo
T_WHITESPACE =>  
T_VARIABLE => $a
+ 
T_LNUMBER => 1
;

Fixer はこのような配列を PhpCsFixer\Tokenizer\Tokens クラスにラップして扱う。
つまり、Fixer は 文字列を直接置換するのではなく、トークン列を編集している

4. トークンが重要な理由

4.1 正確な文法単位で操作できる

トークンを使えば「$a + 1 の中の空白だけを整形」や「コメントを無視して並び替える」など、
文字列処理では難しい安全な修正が可能になる。

4.2 Fixerの実装構造と直結している

PHP-CS-Fixer では次のように使われる。

  • Tokenizer:token_get_all() を拡張し、トークン列を生成
  • TokensAnalyzer:トークン間の関係(ブロック・関数・クラスなど)を解析
  • Fixer:ルールに応じてトークン列を再構成して出力

つまり、字句トークンを理解すれば Fixer の処理フローを自然に追えるようになる。

5. トークンの種類と確認方法

PHPには数百種類のトークンがある。
token_name() を使えば整数IDから名前に変換できる。

var_dump(token_name(T_FUNCTION)); // "T_FUNCTION"

トークン定数の一覧は公式リファレンスにある。
https://www.php.net/manual/ja/tokens.php

学ぶときは次のカテゴリを意識すると理解しやすい。

カテゴリ 代表トークン 用途
構文 T_FUNCTION, T_CLASS, T_IF, T_ELSE 構造認識
型・変数 T_VARIABLE, T_STRING 識別子や名前
コメント T_COMMENT, T_DOC_COMMENT ドキュメント整形系Fixerで使用
空白 T_WHITESPACE 最も頻繁に操作されるトークン
定数・数値 T_LNUMBER, T_CONSTANT_ENCAPSED_STRING 値関連

6. Fixerに進む前に理解しておくこと

Fixerを読む前に、次の3点を押さえておくと理解がスムーズ。

  1. トークンは配列の順序で意味がある
     修正時はインデックスを維持しながら挿入・削除を行う。
  2. Tokens クラスはトークン配列をラップし、編集操作を提供する
     insertAt(), clearAt(), getNextMeaningfulToken() などのメソッドで操作できる。
  3. Fixerは「どのトークンをどう直すか」を1ルール単位で定義している
     isCandidate(), applyFix() などのメソッドがそれに該当する。

7. 次のステップ

ここまで理解できたら、次に進むとよい対象は次の3つ。

  • PhpCsFixer\Tokenizer\Tokens クラスを読む(内部で token_get_all() をどう扱っているか)
  • WhitespaceFixerConfig など単純なFixerを読む
  • FixCommandFixerInterfaceTokens の流れを確認する

8. まとめ

段階 学ぶ目的 理解ポイント
字句解析 ソースをトークン列に分解 token_get_all / token_name
トークン構造 トークンの型と順序 T_定数・記号・空白
Tokensクラス トークン配列の編集API insertAt / clearAt
Fixer設計 トークン列の自動修正 isCandidate / applyFix

この段階でのゴールは、
「PHP-CS-FixerはPHPコードをトークン単位で解析し、ルールごとに変換して整形している」
という構造をイメージできるようになること。

Discussion