はじめに
前回の記事では、現在のファイルの絶対パスを取得する __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__とは独立した汎用関数 |
よくある落とし穴(注意点)
getcwd()との混同に注意する__DIR__は常にファイル自身が存在する場所を指しますが、getcwd()はスクリプトを実行した際のカレントワーキングディレクトリを返します。この2つは、実行方法によって異なる値になることがあるため、混同しないようにしましょう(例7を参照)。- 末尾にスラッシュが含まれない
__DIR__の値には末尾のスラッシュ(/)が含まれません。パスを連結する際は、__DIR__ . '/path/to/file'のように、自分でスラッシュを追加する必要があります。 - 複数階層を遡る際は
dirname()の第2引数を活用する PHP 7.0以降、dirname()の第2引数に遡る階層数を指定できます。dirname(__DIR__, 2)のように書くことで、複数回dirname()をネストさせるよりも簡潔にプロジェクトルートなどを特定できます(例5を参照)。 - シンボリックリンク環境での挙動は
__FILE__と同様__DIR__も__FILE__と同様に、シンボリックリンクを解決した実体のディレクトリパスを返します。 - PHP 5.3より前のバージョンとの互換性が必要な場合 非常に古いレガシーシステムとの互換性を維持する必要がある場合(現在ではまれなケースです)、
__DIR__の代わりにdirname(__FILE__)を使う必要があります。現代のPHP開発では、基本的にこの点を意識する必要はありません。
まとめ
| 観点 | まとめ |
|---|---|
| 何をする定数か | それが記述されているファイルが存在するディレクトリの絶対パスに置き換わる |
| 主な用途 | Composerのautoload読み込み、相対パスでのファイル・テンプレート読み込み、設定ファイルの特定 |
__FILE__との関係 | dirname(__FILE__)と同じ値を、より簡潔に取得できる |
getcwd()との違い | スクリプト自身の場所を指す(実行時のカレントディレクトリとは異なる) |
| 注意点 | 末尾スラッシュが含まれないこと、複数階層を遡る際はdirname()の第2引数が便利 |
__DIR__ は、PHP開発において最も頻繁に使われるマジック定数の一つであり、特に require __DIR__ . '/vendor/autoload.php'; という書き方は、ほぼすべてのComposerベースのプロジェクトで目にする定番パターンです。実行時のカレントディレクトリに依存しない、堅牢なパス解決を実現するために欠かせない存在です。
