[PHP]開発者のための「get_included_files」関数徹底解説:パフォーマンス最適化と応用テクニック

PHP

こんにちは!今回はPHPのデバッグやパフォーマンス最適化に役立つ「get_included_files」関数について詳しく解説します。この関数は実行中のスクリプトで読み込まれたすべてのファイルリストを取得できる便利な関数ですが、その活用方法についてはあまり知られていません。

get_included_files関数とは?

get_included_files関数は、現在のスクリプト実行中にincludeinclude_oncerequirerequire_onceなどの関数によって読み込まれたすべてのファイルの一覧を配列として返します。この関数は別名としてget_required_filesも使用できます(同じ機能です)。

基本的な使い方

// 読み込まれたファイル一覧を取得
$includedFiles = get_included_files();

// 一覧を表示
echo "<h3>読み込まれたファイル一覧:</h3>";
echo "<ol>";
foreach ($includedFiles as $index => $filename) {
    echo "<li>" . htmlspecialchars($filename) . "</li>";
}
echo "</ol>";

// 読み込まれたファイル数を表示
echo "合計 " . count($includedFiles) . " ファイルが読み込まれました。";

最初の要素(インデックス0)は常にメインスクリプト自身(エントリーポイント)になります。

実践的な活用例

1. アプリケーションのメモリ使用量分析

大規模なアプリケーションのメモリ使用量を分析する際に役立ちます:

function analyze_includes() {
    $files = get_included_files();
    $totalSize = 0;
    $fileDetails = [];
    
    foreach ($files as $file) {
        $size = filesize($file);
        $totalSize += $size;
        $fileDetails[] = [
            'path' => $file,
            'size' => $size,
            'size_formatted' => round($size / 1024, 2) . ' KB'
        ];
    }
    
    // サイズでソート(大きい順)
    usort($fileDetails, function($a, $b) {
        return $b['size'] - $a['size'];
    });
    
    echo "<h3>メモリ使用量分析</h3>";
    echo "<p>合計読み込みファイル数: " . count($files) . "</p>";
    echo "<p>合計サイズ: " . round($totalSize / 1024, 2) . " KB</p>";
    
    echo "<table border='1' cellpadding='5'>";
    echo "<tr><th>ファイルパス</th><th>サイズ</th></tr>";
    
    foreach ($fileDetails as $detail) {
        echo "<tr>";
        echo "<td>" . htmlspecialchars($detail['path']) . "</td>";
        echo "<td align='right'>" . $detail['size_formatted'] . "</td>";
        echo "</tr>";
    }
    
    echo "</table>";
    
    return [
        'count' => count($files),
        'total_size' => $totalSize,
        'details' => $fileDetails
    ];
}

// 分析実行
$analysis = analyze_includes();

2. 重複インクルードの検出

複数回読み込まれているファイルを検出する例:

function detect_duplicate_includes() {
    $files = get_included_files();
    $basenames = [];
    $duplicates = [];
    
    foreach ($files as $file) {
        $basename = basename($file);
        
        if (!isset($basenames[$basename])) {
            $basenames[$basename] = [$file];
        } else {
            $basenames[$basename][] = $file;
            $duplicates[$basename] = $basenames[$basename];
        }
    }
    
    if (empty($duplicates)) {
        echo "<p>重複するファイル名は見つかりませんでした。</p>";
    } else {
        echo "<h3>同じファイル名が複数のパスで見つかりました:</h3>";
        echo "<ul>";
        
        foreach ($duplicates as $basename => $paths) {
            echo "<li><strong>" . htmlspecialchars($basename) . "</strong>:";
            echo "<ul>";
            
            foreach ($paths as $path) {
                echo "<li>" . htmlspecialchars($path) . "</li>";
            }
            
            echo "</ul></li>";
        }
        
        echo "</ul>";
        echo "<p>注意: 同じファイル名でも異なるディレクトリのファイルである可能性があります。</p>";
    }
    
    return $duplicates;
}

// 重複検出を実行
$duplicates = detect_duplicate_includes();

3. オートローダーの効率分析

オートローダーが効率的に動作しているか分析する例:

function analyze_autoloader_efficiency() {
    // 初期状態のインクルードファイル数を記録
    $initialFiles = get_included_files();
    
    // テスト用にいくつかのクラスをロード
    $testClasses = [
        'SomeNamespace\\ClassA',
        'SomeNamespace\\ClassB',
        'AnotherNamespace\\ClassC'
    ];
    
    $loadedClasses = [];
    $failedClasses = [];
    
    foreach ($testClasses as $class) {
        if (class_exists($class, true)) {
            $loadedClasses[] = $class;
        } else {
            $failedClasses[] = $class;
        }
    }
    
    // クラスロード後のインクルードファイル
    $afterFiles = get_included_files();
    $newFiles = array_diff($afterFiles, $initialFiles);
    
    echo "<h3>オートローダー効率分析</h3>";
    echo "<p>ロードされたクラス数: " . count($loadedClasses) . "</p>";
    echo "<p>失敗したクラス数: " . count($failedClasses) . "</p>";
    echo "<p>新たに読み込まれたファイル数: " . count($newFiles) . "</p>";
    
    if (count($newFiles) > count($loadedClasses)) {
        echo "<p>警告: 実際にロードされたクラス数よりも多くのファイルが読み込まれています。</p>";
    }
    
    return [
        'loaded_classes' => $loadedClasses,
        'failed_classes' => $failedClasses,
        'new_files' => $newFiles
    ];
}

// オートローダー分析を実行
$autoloaderAnalysis = analyze_autoloader_efficiency();

4. パフォーマンス最適化のためのデバッグツール

ページロード時に不要なファイルが読み込まれていないか確認する例:

function create_performance_debug_tool() {
    // 初期状態を記録
    $startTime = microtime(true);
    $startMemory = memory_get_usage();
    $startFiles = get_included_files();
    
    // 処理中にフックを登録
    register_shutdown_function(function() use ($startTime, $startMemory, $startFiles) {
        $endTime = microtime(true);
        $endMemory = memory_get_usage();
        $endFiles = get_included_files();
        
        $newFiles = array_diff($endFiles, $startFiles);
        $loadTime = round(($endTime - $startTime) * 1000, 2);
        $memoryUsage = round(($endMemory - $startMemory) / 1024, 2);
        
        echo "<!-- Performance Debug Information -->\n";
        echo "<!-- Load Time: {$loadTime} ms -->\n";
        echo "<!-- Memory Usage: {$memoryUsage} KB -->\n";
        echo "<!-- Files Loaded: " . count($endFiles) . " -->\n";
        
        if (isset($_GET['debug']) && $_GET['debug'] === 'files') {
            echo "<div style='background:#f5f5f5;padding:10px;margin-top:20px;border:1px solid #ddd;'>";
            echo "<h3>パフォーマンスデバッグ情報</h3>";
            echo "<p>読み込み時間: {$loadTime} ms</p>";
            echo "<p>メモリ使用量: {$memoryUsage} KB</p>";
            echo "<p>読み込まれたファイル数: " . count($endFiles) . "</p>";
            
            echo "<h4>後から読み込まれたファイル:</h4>";
            echo "<ul>";
            foreach ($newFiles as $file) {
                echo "<li>" . htmlspecialchars($file) . "</li>";
            }
            echo "</ul>";
            echo "</div>";
        }
    });
}

// デバッグツールを開始
if (isset($_GET['debug'])) {
    create_performance_debug_tool();
}

実用的なクラス:IncludeAnalyzer

実際に使えるクラスとして、IncludeAnalyzerを作成してみましょう:

class IncludeAnalyzer {
    private $initialFiles;
    private $startTime;
    private $startMemory;
    
    public function __construct() {
        $this->initialFiles = get_included_files();
        $this->startTime = microtime(true);
        $this->startMemory = memory_get_usage();
    }
    
    public function getFilesLoaded() {
        return get_included_files();
    }
    
    public function getNewFilesLoaded() {
        $currentFiles = get_included_files();
        return array_diff($currentFiles, $this->initialFiles);
    }
    
    public function getTotalFileSize() {
        $totalSize = 0;
        foreach (get_included_files() as $file) {
            $totalSize += filesize($file);
        }
        return $totalSize;
    }
    
    public function getMemoryUsage() {
        return memory_get_usage() - $this->startMemory;
    }
    
    public function getExecutionTime() {
        return microtime(true) - $this->startTime;
    }
    
    public function generateReport($detailed = false) {
        $currentFiles = get_included_files();
        $newFiles = $this->getNewFilesLoaded();
        $totalSize = $this->getTotalFileSize();
        $execTime = $this->getExecutionTime();
        $memoryUsage = $this->getMemoryUsage();
        
        $report = [
            'total_files' => count($currentFiles),
            'new_files' => count($newFiles),
            'total_size' => $totalSize,
            'total_size_formatted' => round($totalSize / 1024, 2) . ' KB',
            'execution_time' => round($execTime * 1000, 2) . ' ms',
            'memory_usage' => round($memoryUsage / 1024, 2) . ' KB'
        ];
        
        if ($detailed) {
            $fileDetails = [];
            foreach ($currentFiles as $file) {
                $size = filesize($file);
                $fileDetails[] = [
                    'path' => $file,
                    'size' => $size,
                    'size_formatted' => round($size / 1024, 2) . ' KB',
                    'is_new' => in_array($file, $newFiles)
                ];
            }
            $report['file_details'] = $fileDetails;
        }
        
        return $report;
    }
    
    public function displayReport() {
        $report = $this->generateReport(true);
        
        echo "<div style='background:#f5f5f5;padding:15px;margin:15px 0;border-radius:5px;'>";
        echo "<h3>ファイル読み込み分析レポート</h3>";
        echo "<p>合計ファイル数: " . $report['total_files'] . "</p>";
        echo "<p>新規ファイル数: " . $report['new_files'] . "</p>";
        echo "<p>合計サイズ: " . $report['total_size_formatted'] . "</p>";
        echo "<p>実行時間: " . $report['execution_time'] . "</p>";
        echo "<p>メモリ使用量: " . $report['memory_usage'] . "</p>";
        
        echo "<h4>読み込まれたファイル一覧:</h4>";
        echo "<table border='1' cellpadding='5' style='border-collapse:collapse;width:100%;'>";
        echo "<tr><th>ファイルパス</th><th>サイズ</th><th>状態</th></tr>";
        
        foreach ($report['file_details'] as $detail) {
            echo "<tr>";
            echo "<td>" . htmlspecialchars($detail['path']) . "</td>";
            echo "<td align='right'>" . $detail['size_formatted'] . "</td>";
            echo "<td>" . ($detail['is_new'] ? '新規' : '初期') . "</td>";
            echo "</tr>";
        }
        
        echo "</table>";
        echo "</div>";
    }
}

// 使用例
$analyzer = new IncludeAnalyzer();

// 何かの処理
require_once 'some_file.php';
include 'another_file.php';

// レポート表示
$analyzer->displayReport();

注意点と制限事項

  1. パフォーマンスへの影響: get_included_files自体はパフォーマンスへの影響が小さいですが、頻繁に呼び出すと若干のオーバーヘッドが生じる可能性があります。
  2. 相対パス解決: 返される配列内のパスは絶対パスなので、相対パスで読み込んだファイルも絶対パスとして表示されます。
  3. 自動インクルード: オートローダーによって自動的に読み込まれるファイルも含まれます。
  4. 発展的なフレームワーク: LaravelやSymfonyなどの最新のフレームワークでは、独自のクラスローディングメカニズムを使用しているため、すべてのファイルがget_included_filesで取得できるわけではありません。

まとめ

get_included_files関数は、PHPアプリケーションの最適化やデバッグにおいて非常に有用なツールです。

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