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点を押さえておくと理解がスムーズ。
- トークンは配列の順序で意味がある
修正時はインデックスを維持しながら挿入・削除を行う。 -
Tokensクラスはトークン配列をラップし、編集操作を提供する
insertAt(),clearAt(),getNextMeaningfulToken()などのメソッドで操作できる。 - Fixerは「どのトークンをどう直すか」を1ルール単位で定義している
isCandidate(),applyFix()などのメソッドがそれに該当する。
7. 次のステップ
ここまで理解できたら、次に進むとよい対象は次の3つ。
-
PhpCsFixer\Tokenizer\Tokensクラスを読む(内部でtoken_get_all()をどう扱っているか) -
WhitespaceFixerConfigなど単純なFixerを読む -
FixCommand→FixerInterface→Tokensの流れを確認する
8. まとめ
| 段階 | 学ぶ目的 | 理解ポイント |
|---|---|---|
| 字句解析 | ソースをトークン列に分解 | token_get_all / token_name |
| トークン構造 | トークンの型と順序 | T_定数・記号・空白 |
| Tokensクラス | トークン配列の編集API | insertAt / clearAt |
| Fixer設計 | トークン列の自動修正 | isCandidate / applyFix |
この段階でのゴールは、
「PHP-CS-FixerはPHPコードをトークン単位で解析し、ルールごとに変換して整形している」
という構造をイメージできるようになること。
Discussion