レガシーPHPリファクタ 17:config.phpの返り値化によるグローバル汚染の解消

レガシーなPHPアプリケーションでよく見かけるアンチパターンのひとつが、設定ファイルがグローバル変数を汚染する設計です。 今回は、config.php でグローバル変数に代入していた方式を、設定配列を直接 return する方式へリファクタリングした事例をご紹介します。


1. 修正前後のコード比較

修正前:グローバル変数への依存

修正前は、設定ファイル内で一時変数($dbHost など)を展開した上で、グローバル空間にある $config 配列に代入していました。 呼び出し側(index.php)は、そのグローバル変数が存在することを暗黙的に前提として処理を進めていました。

config.php:

<?php

// $_ENV または getenv から安全に取得(型を string に確定させる)
$dbHost     = envString('DB_HOST');
$dbDatabase = envString('DB_DATABASE');
$dbUser     = envString('DB_USER');
$dbPassword = envString('DB_PASSWORD');

// PDO設定
$config['dsn'] = sprintf('mysql:dbname=%s;host=%s', $dbDatabase, $dbHost);
$config['db_user'] = $dbUser;
$config['db_password'] = $dbPassword;

index.php:

require_once __DIR__ . '/config.php';

/**
 * @var array{dsn: string, db_user: string, db_password: string} $config
 */
// 全件数を調べて、Pagerを初期化する
$cms = new CMS($config['dsn'], $config['db_user'], $config['db_password']);

修正後:設定配列の return とローカル変数での受け取り

修正後では、一時変数を廃止し、設定データを格納した配列を直接 return するように変更しました。 また、ファイルパスも config/config.php へ整理し、呼び出し側では require の戻り値としてローカル変数 $config に受け取っています。

config/config.php:

<?php

// $_ENV または getenv から安全に取得(型を string に確定させる)
return [
    'dsn'         => sprintf('mysql:dbname=%s;host=%s', envString('DB_DATABASE'), envString('DB_HOST')),
    'db_user'     => envString('DB_USER'),
    'db_password' => envString('DB_PASSWORD'),
];

index.php:

/**
 * @var array{dsn: string, db_user: string, db_password: string, perPage: int, sort_key: string, sort_direction: string} $config
 */
$config = require_once __DIR__ . '/config/config.php';

// ----- メイン処理・データ操作 -----
$cms = new CMS($config['dsn'], $config['db_user'], $config['db_password']);

2. このリファクタリングによる4つのメリット

グローバル変数依存から脱却し、配列を返す設計に改めたことで、コードの保守性・安全性・テスト容易性が多方面から向上しました。

1. グローバル汚染の防止(カプセル化の向上)

修正前の方式では、設定ファイルを読み込むと $CONFIG という大元の変数だけでなく、内部で使用していた $dbHost や $dbDatabase といった一時的な説明変数までもが、そのままグローバル空間に生えてしまっていました。

そのため、他のファイルや予期せぬ場所で同じ変数名が意図せず上書きされたり、グローバル変数の乱立によって「どの変数がどこで定義され、何に依存しているのか」の追跡が極めて困難になるリスクがありました。

修正後は、不要な一時変数を廃止し、require の戻り値としてローカル変数 $config に明示的に受け取る設計に変更しました。これにより、設定処理で扱う変数のスコープが適切にファイル内に閉じられ、意図しない変数の衝突や汚染を完全に防ぐことができます。

2. 依存関係と「入力・出力」の明確化

設定ファイルが「値を返す(return)」という明確なインターフェースを持つため、コードの予測可能性が上がります。「このファイルを読み込めば、純粋な設定データが取得できる」という単一の責務(Single Responsibility)になり、関数やモジュールと同じようにデータ構造を安全に受け渡せるようになります。

3. 静的解析やIDE補完の精度向上

PHPStanなどの静的解析ツールやIDE(PhpStormなど)において、グローバル変数は型追跡が複雑になりがちです。ローカル変数 $config に直接 require の結果を受け取ることで、PHPDocの @var アノテーションとの紐付けが確実になり、タイポの検知やコード補完の精度が向上します。

4. テスト容易性の向上(Testability)

将来的にユニットテストや自動テストを導入する際、グローバル変数に依存していると、テストごとにグローバル状態をリセットする手間が発生します。設定配列を返す形にしておけば、テスト時にモックの設定配列を簡単に注入(インジェクション)できるようになります。


まとめ

レガシーコードによく見られる「ファイルを読み込ませてグローバル変数を勝手に生やさせる」という手法は、スクリプトの規模が大きくなるにつれてコードの追跡を困難にする大きな原因になります。

今回のリファクタリングにおける特筆すべきポイントは、呼び出し側(index.php)の修正が実質「require の結果を $config で受けるように書き換えただけ」という極めてシンプルな変更に留まる点です。

  • 修正のコストとリスクが非常に小さい(数行の書き換えのみ)
  • 得られるメリットが絶大(グローバル汚染の解消、静検の精度向上、テスト容易性の確保など)

設定ファイルを「値を返す純粋なデータソース」として扱うことは、現代的なPHPアプリケーション設計の基本であり、PHPStanなどの静的解析や自動テストを導入する上でも極めて有効な改善です。 レガシーPHPシステムの保守を行う際は、本格的な作業前の Tidy 活動として、こうした設定ファイルの小さなリファクタリングから試してみてください。

関連プルリクエスト

refactor(chapter4_6): config.php を設定配列を return するようにしました by ninton · Pull Request #392 · ninton/smartybook
概要Smarty用の index.conf を config.php へ集約するための準備。変更内容config.php を設定配列を return するようにしましたrequire_once config.php の return結果を ...
refactor(chapter4_6): config.php の一時変数を廃止しグローバル汚染を解消 by ninton · Pull Request #605 · ninton/smartybook
概要config.php 内において、設定値を組み立てるために使用していた一時変数($dbHost, $dbDatabase, $dbUser, $dbPassword, $dsn)を削除し、返却する配列リテラル内に直接埋め込むように変更し...
レガシーPHPリファクタ 17:config.phpの返り値化によるグローバル汚染の解消
Smarty動的Webサイト構築入門サンプルソース. Contribute to ninton/smartybook development by creating an account on GitHub.
タイトルとURLをコピーしました