レガシーPHPリファクタ 2:「たかが変数名」とバカにできない!安全にコードの可読性とAI精度を引き上げるリネーム戦略

レガシーPHPリファクタ 2:「たかが変数名」とバカにできない!安全にコードの可読性とAI精度を引き上げるリネーム戦略
Smarty動的Webサイト構築入門サンプルソース. Contribute to ninton/smartybook development by creating an account on GitHub.

レガシーなPHPコードを読んでいるとき、「この変数、中身に何が入っているんだ…?」と頭を抱えたことはありませんか?

動的型付け言語では変数名は(下手したら唯一の)型アノテーションの側面があります。 今回は、レガシーPHPにおける「変数名のリネーム」に焦点を当て、具体的なリファクタリング例と、なぜそれが人間だけでなくAIや静的解析ツールにとっても重要なのかを解説します。


なぜ今、変数名のリネームなのか?

変数名を変えるだけのリファクタリングには、大きなメリットが3つあります。

  1. 既存機能を壊すリスクが極めて低い ロジック自体には手を加えないため、デグレ(先祖返りや機能破壊)のリスクが非常に低いです。
  2. PhpStorm や PHPStan で安全に作業できる IDE(PhpStorm)のリネーム機能を使えば、スコープ内の変数を安全に一括置換できます。さらに、修正ミスがあっても PHPStan などの静的解析ツールを実行すれば一発で検出できます。
  3. 「人間」と「AI」の両方にメリットがある 可読性が上がるのはもちろんですが、現代の開発においては GitHub Copilot などの AI 補完ツールの解析精度が向上する という大きな副次効果があります。

それでは、実際にSmartybookのリファクタPR(Pull Request)をベースに、具体的な改善パターンを見ていきましょう。


パターン別:変数名改善の具体例

1. 「文字列」なのか「ファイルパス」なのかを明確にする

  • 修正前: $csv / $file
  • 修正後: $csvFilePath / $fileHandle
// 修正前:$csv に文字列が入っているのかデータ自体が入っているのか曖昧
$csv = 'data/users.csv';
$fp = fopen($csv, 'r');

// 修正後:単なる文字列ではなく「ファイルパス」であることを明示
$csvFilePath = 'data/users.csv';
$fileHandle = fopen($csvFilePath, 'r');

なぜ変えるのか?

$csv だと「CSV文字列データ」なのか「ファイルパス」なのかが判断できません。 また、fopen の戻り値を $file や $fp にしがちですが、$file はパス(string)と混同しやすく、2文字の短縮名($fp)よりも $fileHandle(または $handle)とする方が意図が自己説明的になります。PHPStanの @param resource $fileHandle といった型注釈とも相性抜群です。

参考PR


2. 概念名だけでなく「遷移先URL/パス」であることを明示する

  • 修正前: $admin / $home
  • 修正後: $adminURL / $homeURL
<!-- 修正前:変数名を見ただけでは何が入っているか不明 -->
<a href="<?php echo $admin; ?>">管理画面</a>

<!-- 修正後:URL/パスであることが一目でわかる -->
<a href="<?php echo $adminURL; ?>">管理画面</a>

なぜ変えるのか?

$admin や $home という名称だけでは、管理者オブジェクトなのか、設定フラグなのか、URL文字列なのかが伝わりません。末尾に URL をつけることで、HTML描画時の文脈が明示的になります。

参考PR


3. CSVの1行データは公式ドキュメント由来の $row に統一する

  • 修正前: $arr
  • 修正後: $row
// 修正前
while ($arr = fgetcsv($fileHandle)) { ... }

// 修正後:表の「1行(配列)」であることが直感的に伝わる
while ($row = fgetcsv($fileHandle)) { ... }

公式ドキュメントの命名比較

fgetcsv や str_getcsv 周辺ではいくつかの命名が見られますが、用途に応じて使い分けるのがベストです。

変数名由来・ニュアンス評価と推奨理由
$rowテーブルやファイルの「1行」一番おすすめ。 直感的に1行分のデータ(配列)だと伝わり、while ($row = ...) との相性が抜群。
$fieldsCSVの要素(フィールド)の集まり。
若干、フィールド名の配列やフィールド名→値のKeyValue配列のニュアンスを感じます。
公式では主に書き込み(fputcsv)側の引数名でよく使われます。
若干、入っているものが「フィールド名」か「フィールドの値」なのかが曖昧。
$data抽象的な「データ」汎用的ですが、1行分なのか全体(全行)なのかが曖昧になりやすいのが難点。

1行($row)を起点として、後続処理で $row[0] にアクセスしたり連想配列へ詰め替えたりするメンタルモデルが非常にすっきりします。

参考PR


4. 表記揺れをなくし、単数・複数形の事故を防ぐ(List 接尾辞)

  • 修正前: $items, $data, $entryArr / $categories
  • 修正後: $entryList / $categoryList
// 修正前:単数/複数の見落とし事故が起きやすい
foreach ($categories as $category) { ... }

// 修正後:コレクションであることが一目でわかり、型定義(array shape)も付けやすい
/** @var list<array{id: int, name: string}> $categoryList */
foreach ($categoryList as $category) { ... }

なぜ変えるのか?

  1. タイポ・実装ミス防止: category(単数)と categories(複数)は1文字違いで視認しにくく、初心者や写経時のレガシーコード事故の定番です。$categoryList にすることで単体とコレクションの区別が明確になります。
  2. ドメイン用語の統一: $items や $data のような抽象名をやめ、サービス内の概念(Entry など)に名前を揃えます。
  3. 静的解析・PHPStanとの親和性: list<T> 記法や array shape(list<array{...}>)と意図が完全一致するため、型のセルフドキュメント化が進みます。

参考PR


まとめ:安全なリファクタリングが未来の開発を楽にする

レガシーPHPのリファクタリングは、ロジックを大きく書き換えることだけが手段ではありません。

  1. $csvFilePath や $fileHandle のように型の誤解を防ぐ命名にする
  2. List 接尾辞を使って単複の事故を防ぎ、静的解析(PHPStan)と連携する
  3. 自己説明的なコードにして、人間とAI(Copilot等)の文脈理解度を高める

まずは1つのファイル、1つの変数名から。小さなリネームの積み重ねが、将来の自分やチームメンバーの負担を大きく減らしてくれます。

タイトルとURLをコピーしました