[PHP]__DIR__とは?現在のファイルが存在するディレクトリを取得するマジック定数を徹底解説

PHP

はじめに

前回の記事では、現在のファイルの絶対パスを取得する __FILE__ を解説し、その中で「ディレクトリパスだけが必要な場合は __DIR__ の方が簡潔」と触れました。今回は、その __DIR__ を正面から取り上げます。

__DIR__ は、それが記述されているPHPファイルが存在するディレクトリの絶対パスに、コンパイル時に置き換えられるマジック定数です。PHP 5.3で導入されたこの定数は、実質的に dirname(__FILE__) と同じ値を返しますが、より簡潔に書けるという利点があります。require/include でのファイル読み込み、Composerのオートロード設定、相対パスで配置されたリソースファイルへのアクセスなど、PHP開発において最も頻繁に使われるマジック定数の一つと言えます。本記事では基本的な使い方から実践的な活用例まで詳しく解説します。


定数概要

項目内容
定数名__DIR__
種別マジック定数
値の型文字列(string)
値の内容そのコードが記述されているファイルが存在するディレクトリの絶対パス
対応バージョンPHP 5.3.0以降
等価な古い書き方dirname(__FILE__)
末尾のスラッシュ含まれない(例: /var/www/app、/var/www/app/ ではない)

__FILE__との関係(イメージ図)

  ディレクトリ構造
  /var/www/app/
  └── src/
      └── helper.php   ← このファイル内に記述

  helper.php の中身:
  <?php
  echo __FILE__ . "\n";  // "/var/www/app/src/helper.php"
  echo __DIR__  . "\n";  // "/var/www/app/src"
              │
              ▼
  __DIR__ は常に dirname(__FILE__) と同じ値になる
  (PHP 5.3以降では__DIR__の使用が簡潔で推奨される)

ポイントは、__DIR__ が**dirname(__FILE__) という頻出パターンを1つの定数で表現できる**という点です。PHP 5.3より前のバージョンのコードでは dirname(__FILE__) という書き方が一般的でしたが、現在はほぼすべてのプロジェクトで __DIR__ が使われています。


実践サンプル7選

例1:基本的な使い方

<?php

echo 'このファイルのディレクトリ: ' . __DIR__ . PHP_EOL;

// dirname(__FILE__)と__DIR__が同じ値であることを確認する
var_dump(__DIR__ === dirname(__FILE__));

例2:Composerのautoload.phpを読み込む定番パターン

<?php

/**
 * __DIR__を基準にすることで、
 * このファイルがどこから実行されても正しくautoload.phpを読み込める
 */
require __DIR__ . '/vendor/autoload.php';

echo 'オートローダーを読み込みました' . PHP_EOL;

例3:相対的なディレクトリ構成を前提とした複数ファイルの読み込み

<?php

class ModuleLoader
{
    /**
     * __DIR__を使うことで、カレントディレクトリに依存せず
     * 常に確実にモジュールファイルを探せる
     */
    public function loadAllModules(): array
    {
        $modulesDir = __DIR__ . '/modules';
        $loaded = [];

        foreach (glob($modulesDir . '/*.php') as $file) {
            $loaded[] = basename($file, '.php');
            require_once $file;
        }

        return $loaded;
    }
}

// $loader = new ModuleLoader();
// print_r($loader->loadAllModules());

例4:テンプレートファイルへのパスを解決するレンダラー

<?php

class SimpleTemplateRenderer
{
    private string $templatesDir;

    public function __construct()
    {
        // クラス定義ファイルからの相対パスでテンプレートディレクトリを特定する
        $this->templatesDir = __DIR__ . '/templates';
    }

    public function render(string $templateName, array $data = []): string
    {
        $path = $this->templatesDir . '/' . $templateName . '.php';

        if (!file_exists($path)) {
            throw new RuntimeException("テンプレートが見つかりません: {$path}");
        }

        extract($data);
        ob_start();
        include $path;
        return ob_get_clean();
    }
}

// $renderer = new SimpleTemplateRenderer();
// echo $renderer->render('welcome', ['name' => '太郎']);

例5:プロジェクトルートを基準とした設定ファイルの読み込み

<?php

class ProjectPaths
{
    /**
     * __DIR__から相対的に遡ることで、
     * プロジェクトルートのパスを特定する
     * (このファイルが /app/src/Config/ にあると仮定)
     */
    public static function root(): string
    {
        return dirname(__DIR__, 2); // 2階層上に遡る
    }

    public static function storage(): string
    {
        return self::root() . '/storage';
    }
}

// echo ProjectPaths::root() . PHP_EOL;
// echo ProjectPaths::storage() . PHP_EOL;

例6:ログファイルの出力先を固定するロガー

<?php

class FixedLocationLogger
{
    private string $logDir;

    public function __construct()
    {
        /**
         * __DIR__を使うことで、どのスクリプトから呼ばれても
         * ログの出力先が常に同じ固定の場所になる
         */
        $this->logDir = __DIR__ . '/logs';

        if (!is_dir($this->logDir)) {
            mkdir($this->logDir, 0755, true);
        }
    }

    public function log(string $message): void
    {
        $logFile = $this->logDir . '/app.log';
        $entry = '[' . date('Y-m-d H:i:s') . "] {$message}\n";
        file_put_contents($logFile, $entry, FILE_APPEND);
    }
}

$logger = new FixedLocationLogger();
// $logger->log('アプリケーションが起動しました');

例7:異なるディレクトリにあるファイル間でのパス解決の違いを確認する

<?php

// このファイルが /app/index.php にあると仮定
function demonstratePathResolution(): void
{
    echo '__DIR__ (index.php内): ' . __DIR__ . PHP_EOL;

    // getcwd()はカレントワーキングディレクトリ(実行時のディレクトリ)を返すため、
    // __DIR__とは異なる結果になることがある
    echo 'getcwd() (実行時のディレクトリ): ' . getcwd() . PHP_EOL;
}

demonstratePathResolution();
// スクリプトをどのディレクトリから実行しても、
// __DIR__は常にこのファイル自身の場所を指す

関連機能との比較

機能役割__DIR__との違い
__DIR__現在のファイルが存在するディレクトリの絶対パスを取得本記事の対象。PHP 5.3以降で利用可能
__FILE__現在のファイルの絶対パス(ファイル名含む)を取得ファイル名まで含む、より完全なパス情報(前回記事を参照)
dirname(__FILE__)__FILE__からディレクトリ部分を取り出す__DIR__登場以前の書き方で、機能的には同等
getcwd()現在の作業(カレント)ディレクトリを取得スクリプト自身の場所ではなく、実行時のシェル上の位置に依存する
realpath()指定したパスの絶対パスを解決する任意のパス文字列を対象とし、__DIR__とは独立した汎用関数

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

  1. getcwd()との混同に注意する __DIR__ は常にファイル自身が存在する場所を指しますが、getcwd() はスクリプトを実行した際のカレントワーキングディレクトリを返します。この2つは、実行方法によって異なる値になることがあるため、混同しないようにしましょう(例7を参照)。
  2. 末尾にスラッシュが含まれない __DIR__ の値には末尾のスラッシュ(/)が含まれません。パスを連結する際は、__DIR__ . '/path/to/file' のように、自分でスラッシュを追加する必要があります。
  3. 複数階層を遡る際はdirname()の第2引数を活用する PHP 7.0以降、dirname() の第2引数に遡る階層数を指定できます。dirname(__DIR__, 2) のように書くことで、複数回 dirname() をネストさせるよりも簡潔にプロジェクトルートなどを特定できます(例5を参照)。
  4. シンボリックリンク環境での挙動は__FILE__と同様 __DIR__ も __FILE__ と同様に、シンボリックリンクを解決した実体のディレクトリパスを返します。
  5. PHP 5.3より前のバージョンとの互換性が必要な場合 非常に古いレガシーシステムとの互換性を維持する必要がある場合(現在ではまれなケースです)、__DIR__ の代わりに dirname(__FILE__) を使う必要があります。現代のPHP開発では、基本的にこの点を意識する必要はありません。

まとめ

観点まとめ
何をする定数かそれが記述されているファイルが存在するディレクトリの絶対パスに置き換わる
主な用途Composerのautoload読み込み、相対パスでのファイル・テンプレート読み込み、設定ファイルの特定
__FILE__との関係dirname(__FILE__)と同じ値を、より簡潔に取得できる
getcwd()との違いスクリプト自身の場所を指す(実行時のカレントディレクトリとは異なる)
注意点末尾スラッシュが含まれないこと、複数階層を遡る際はdirname()の第2引数が便利

__DIR__ は、PHP開発において最も頻繁に使われるマジック定数の一つであり、特に require __DIR__ . '/vendor/autoload.php'; という書き方は、ほぼすべてのComposerベースのプロジェクトで目にする定番パターンです。実行時のカレントディレクトリに依存しない、堅牢なパス解決を実現するために欠かせない存在です。

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