[PHP]__FILE__とは?現在のファイルの絶対パスを取得するマジック定数を徹底解説

PHP

はじめに

前回の記事では、コード中の現在行番号を取得するマジック定数 __LINE__ を解説しました。今回取り上げる __FILE__ は、それと並んでよく使われる、現在のファイルの絶対パスを取得するマジック定数です。

__FILE__ は、それが記述されているPHPファイル自身の、シンボリックリンクが解決された完全な絶対パスに、コンパイル時に置き換えられます。設定ファイルの読み込み、相対パスの解決、ログの出力元ファイルの特定、include/require でのパス指定など、ファイルシステム上の自分自身の位置を知る必要がある、非常に多くの場面で活用される基本的な仕組みです。本記事では基本的な使い方から、__DIR__ との使い分け、実践的な活用例まで詳しく解説します。


定数概要

項目内容
定数名__FILE__
種別マジック定数
値の型文字列(string)
値の内容そのコードが記述されているファイルの絶対パス(シンボリックリンク解決済み)
対応バージョンPHP 4以降
関連するマジック定数__DIR__(PHP 5.3以降、dirname(__FILE__)の簡潔な代替)
includeされた場合の挙動呼び出し元ではなく、__FILE__が実際に書かれているファイル自身のパスを返す

パス解決の仕組み(イメージ図)

  ディレクトリ構造
  /var/www/app/
  ├── config/
  │   └── database.php   ← __FILE__がここに書かれている
  └── index.php           ← database.phpをincludeする側

  database.php の中身:
  <?php
  echo __FILE__;
              │
              ▼
  出力: "/var/www/app/config/database.php"
  (index.phpから呼び出されても、
   database.php自身の絶対パスが返る)

ポイントは、__FILE__ がシンボリックリンクを解決した「実際の」絶対パスを返すという点です。もし database.php がシンボリックリンク経由でアクセスされていたとしても、__FILE__ はリンク先の実体のパスを返します。


実践サンプル7選

例1:基本的な使い方

<?php

echo '現在のファイル: ' . __FILE__ . PHP_EOL;
echo 'ファイル名のみ: ' . basename(__FILE__) . PHP_EOL;
echo 'ディレクトリ: ' . dirname(__FILE__) . PHP_EOL;

例2:相対パスでの設定ファイル読み込みを確実にするクラス

<?php

class ConfigLoader
{
    /**
     * __FILE__を基準にすることで、
     * スクリプトがどこから実行されても正しいパスを解決できる
     */
    public function load(): array
    {
        $configPath = dirname(__FILE__) . '/config/settings.php';

        if (!file_exists($configPath)) {
            throw new RuntimeException("設定ファイルが見つかりません: {$configPath}");
        }

        return include $configPath;
    }
}

$loader = new ConfigLoader();
// $config = $loader->load();

例3:ログ出力元ファイルを記録するロガー

<?php

class FileAwareLogger
{
    /**
     * __FILE__を呼び出し元から渡してもらうことで、
     * ログにどのファイルから出力されたかを記録する
     */
    public static function log(string $message, string $sourceFile): void
    {
        $relativePath = str_replace(dirname(__DIR__ ?? '.'), '', $sourceFile);
        echo "[{$relativePath}] {$message}" . PHP_EOL;
    }
}

FileAwareLogger::log('処理を開始しました', __FILE__);

例4:autoloadファイルなしでの簡易クラス読み込み

<?php

// このファイル自身のディレクトリを基準にクラスファイルを読み込む
$classesDir = dirname(__FILE__) . '/classes';

/**
 * Composerのautoloadを使わない簡易的な環境で、
 * __FILE__基準の相対パスでファイルを読み込む典型的なパターン
 */
function loadClass(string $className): void
{
    global $classesDir;
    $path = $classesDir . '/' . $className . '.php';

    if (file_exists($path)) {
        require_once $path;
    }
}

// loadClass('MyClass');

例5:ファイルの更新日時をチェックするキャッシュバスター

<?php

class AssetVersioner
{
    /**
     * __FILE__とfilemtime()を組み合わせて、
     * ファイルの更新日時をバージョン文字列として付与する
     * (ブラウザキャッシュ対策の典型的な手法)
     */
    public static function getVersionedPath(string $relativePath): string
    {
        $fullPath = dirname(__FILE__) . '/public/' . $relativePath;
        $version = file_exists($fullPath) ? filemtime($fullPath) : time();

        return "/{$relativePath}?v={$version}";
    }
}

echo AssetVersioner::getVersionedPath('css/style.css') . PHP_EOL;

例6:現在のファイルがコマンドラインから直接実行されたかを判定する

<?php

/**
 * __FILE__と$_SERVER['SCRIPT_FILENAME'](またはargv[0])を比較することで、
 * このファイルがinclude/requireされたのか、直接実行されたのかを判定できる
 */
function isExecutedDirectly(): bool
{
    if (PHP_SAPI !== 'cli') {
        return false;
    }

    return realpath($_SERVER['argv'][0] ?? '') === realpath(__FILE__);
}

if (isExecutedDirectly()) {
    echo 'このファイルは直接実行されました' . PHP_EOL;
} else {
    echo 'このファイルは他のファイルから読み込まれました' . PHP_EOL;
}

例7:デバッグ情報としてスタック的にファイルパスを記録するクラス

<?php

class FileLocationRecorder
{
    private array $visitedFiles = [];

    /**
     * 複数のファイルをまたいで処理が行われる際、
     * どのファイルを経由したかを記録する
     */
    public function recordVisit(string $file): void
    {
        $this->visitedFiles[] = basename($file);
    }

    public function getTrail(): string
    {
        return implode(' → ', $this->visitedFiles);
    }
}

function stepOne(FileLocationRecorder $recorder): void
{
    $recorder->recordVisit(__FILE__);
}

$recorder = new FileLocationRecorder();
stepOne($recorder);
echo $recorder->getTrail() . PHP_EOL;

関連機能との比較

機能役割__FILE__との違い
__FILE__現在のファイルの絶対パスを取得本記事の対象。ファイル名まで含む完全なパスを返す
__DIR__現在のファイルが存在するディレクトリの絶対パスを取得dirname(__FILE__)の簡潔な代替(PHP 5.3以降)
__LINE__現在の行番号を取得ファイルパスではなく、行番号の情報を提供する(前回記事を参照)
realpath()指定したパスの絶対パスを解決する任意のパス文字列を対象とし、__FILE__自体とは独立した汎用関数
$_SERVER['SCRIPT_FILENAME']実行されたエントリーポイントのファイルパスを取得__FILE__とは異なり、スクリプト全体のエントリーポイントを指す

よくある落とし穴(注意点)

  1. __DIR__の方が簡潔な場合が多い ディレクトリパスだけが必要な場合、わざわざ dirname(__FILE__) と書くよりも、PHP 5.3以降で使える __DIR__ を直接使う方が簡潔です(例2・例4のような処理は __DIR__ で書き換え可能です)。
  2. includeされたファイルでは、そのファイル自身のパスになる __FILE__ は、include/require の呼び出し元ファイルのパスではなく、__FILE__ が実際に記述されているファイル自身のパスを返します。呼び出し階層をまたいだパス取得が必要な場合は、別の方法(debug_backtrace()など)を検討する必要があります。
  3. シンボリックリンク環境での挙動を理解しておく __FILE__ はシンボリックリンクを解決した実体のパスを返すため、シンボリックリンク自体のパスを期待していると、意図と異なる結果になることがあります。
  4. Windows環境でのパス区切り文字の違い __FILE__ が返すパスは、実行環境のOSに応じたディレクトリ区切り文字(Windowsでは \、Unix系では /)を使用します。クロスプラットフォームで動作するコードを書く場合、DIRECTORY_SEPARATOR 定数や str_replace() を使った正規化を検討しましょう。
  5. 本番環境でのパス情報の露出に注意する __FILE__ の値をエラーメッセージなどに含めてユーザーに表示してしまうと、サーバーのディレクトリ構造が露出し、セキュリティ上望ましくない情報開示につながる可能性があります。ログにのみ出力し、ユーザー向けの表示には含めないようにしましょう。

まとめ

観点まとめ
何をする定数かそれが記述されているファイルの、絶対パスに置き換わる
主な用途相対パスでの設定ファイル読み込み、ログの出力元記録、キャッシュバスティング
__DIR__との関係ディレクトリパスのみが必要な場合は__DIR__の方が簡潔
includeされた場合の挙動呼び出し元ではなく、__FILE__自身が書かれているファイルのパスを返す
注意点シンボリックリンクの解決、OSごとのパス区切り文字の違い、本番環境でのパス情報露出への配慮

__FILE__ は、PHPスクリプトが自分自身の位置をファイルシステム上で正確に把握するための、基本的かつ重要なマジック定数です。相対パスに依存する処理を、実行時のカレントディレクトリに左右されずに安定して動作させるために、幅広い場面で活用されています。

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