はじめに
前回の記事では、現在の関数・メソッド名を取得する __FUNCTION__ を解説し、その中で「クラス名が含まれない」という特性に触れました。今回取り上げる __CLASS__ は、それを補う形で、現在のクラスの名前(名前空間を含む完全修飾名)を取得するためのマジック定数です。
__CLASS__ は、それが記述されているクラス定義自身の名前に、コンパイル時に置き換えられます。エラーメッセージへのクラス名の埋め込み、ロギング、自己参照的な処理(new static() の代替としての利用など)において活用されます。本記事では基本的な使い方から、継承時の挙動、static::class との違いまで詳しく解説します。
定数概要
| 項目 | 内容 |
|---|---|
| 定数名 | __CLASS__ |
| 種別 | マジック定数 |
| 値の型 | 文字列(string) |
| 値の内容 | 現在のクラスの名前(名前空間がある場合は完全修飾名) |
| 対応バージョン | PHP 4.3.0以降 |
| トレイト内での挙動 | そのトレイトが使用されているクラスの名前になる |
| 関連する構文 | PHP 5.5以降は ClassName::class という、より汎用的な構文も利用可能 |
継承時の挙動(イメージ図)
class Animal {
public function identify() {
echo __CLASS__; ← これは常に "Animal" を返す
}
}
class Dog extends Animal {
// identify()はオーバーライドしていない
}
$dog = new Dog();
$dog->identify();
│
▼
出力: "Animal"
(実際のインスタンスがDogであっても、
__CLASS__はメソッドが"定義されている"クラス名を返す)
※動的な実行時クラス名("Dog")が欲しい場合は
static::class や get_class($this) を使う必要がある
ポイントは、__CLASS__ がコンパイル時に決定する静的な値であり、「そのコードが書かれているクラス」を表すという点です。継承関係がある場合、実際に実行されているインスタンスのクラス(遅延静的束縛でいう static)とは異なる場合がある点を理解しておく必要があります。
実践サンプル7選
例1:基本的な使い方
<?php
class Product
{
public function describe(): string
{
return '現在のクラス: ' . __CLASS__;
}
}
$product = new Product();
echo $product->describe() . PHP_EOL;
例2:名前空間を含む完全修飾名の確認
<?php
namespace App\Models;
class User
{
public function getClassName(): string
{
// __CLASS__は名前空間込みの完全修飾名を返す
return __CLASS__;
}
}
$user = new User();
echo $user->getClassName() . PHP_EOL; // "App\Models\User"
例3:継承時の挙動を比較するデモ(static::classとの違い)
<?php
class Base
{
public function showClassConstant(): string
{
return __CLASS__; // 常に定義元の"Base"を返す
}
public function showLateStaticBinding(): string
{
return static::class; // 実際の実行時クラス名を返す
}
}
class Derived extends Base
{
}
$derived = new Derived();
echo $derived->showClassConstant() . PHP_EOL; // "Base"
echo $derived->showLateStaticBinding() . PHP_EOL; // "Derived"
例4:例外メッセージにクラス名を自動的に含める
<?php
class ConfigurationException extends \RuntimeException
{
public function __construct(string $reason)
{
// __CLASS__を使うことで、将来クラス名をリネームしても
// メッセージ内のクラス名表記が自動的に追従する
parent::__construct(__CLASS__ . ": {$reason}");
}
}
try {
throw new ConfigurationException('設定ファイルが見つかりません');
} catch (ConfigurationException $e) {
echo $e->getMessage() . PHP_EOL;
}
例5:トレイト内での__CLASS__の挙動を確認する
<?php
trait Loggable
{
public function logSelf(): void
{
// トレイトはそれ自体ではインスタンス化されないため、
// 使用しているクラスの名前が返る
echo __CLASS__ . 'がログ出力を行いました' . PHP_EOL;
}
}
class OrderProcessor
{
use Loggable;
}
class PaymentProcessor
{
use Loggable;
}
(new OrderProcessor())->logSelf(); // "OrderProcessor"
(new PaymentProcessor())->logSelf(); // "PaymentProcessor"
例6:静的コンテキストでのファクトリーメソッドの実装
<?php
class SimpleFactory
{
/**
* 静的メソッド内でも__CLASS__は利用できるが、
* 継承先での動的な生成にはstatic::class(new static())が適する
*/
public static function createWithClassConstant(): self
{
$className = __CLASS__;
return new $className();
}
public static function createWithLateBinding(): static
{
return new static(); // 継承先のクラスがそのままインスタンス化される
}
}
class ExtendedFactory extends SimpleFactory
{
}
$a = ExtendedFactory::createWithClassConstant();
$b = ExtendedFactory::createWithLateBinding();
echo get_class($a) . PHP_EOL; // "SimpleFactory"(__CLASS__は定義元を返すため)
echo get_class($b) . PHP_EOL; // "ExtendedFactory"(遅延静的束縛で正しく継承先になる)
例7:ClassName::class構文との比較
<?php
namespace App\Services;
class PaymentService
{
public function compareClassReferences(): array
{
return [
'magic_constant' => __CLASS__, // 現在実行中のコンテキストのクラス名
'class_syntax' => self::class, // 同様にコンパイル時に解決される完全修飾名
'explicit_name' => PaymentService::class, // クラス名を明示的に指定した場合
];
}
}
$service = new PaymentService();
print_r($service->compareClassReferences());
// すべて同じ値 "App\Services\PaymentService" になる
関連機能との比較
| 機能 | 役割 | __CLASS__との違い |
|---|---|---|
__CLASS__ | 現在のクラス名を取得(マジック定数) | 本記事の対象。コンパイル時に決定する静的な値 |
static::class | 遅延静的束縛による実行時クラス名の取得 | 継承先での実際の呼び出しクラス名を動的に反映する |
self::class | クラス定義時点でのクラス名を取得 | __CLASS__とほぼ同義だが、PHP 5.5以降のより統一的な構文 |
get_class($this) | インスタンスから実行時のクラス名を取得 | $thisが必要なインスタンスメソッド限定だが、実行時の実際のクラスを返す |
__FUNCTION__ / __METHOD__ | 関数・メソッド名を取得 | クラス名ではなく、関数やメソッドの名前の情報を提供する(前回記事を参照) |
よくある落とし穴(注意点)
- 継承時は「定義元のクラス名」を返す これが最も重要な注意点です。
__CLASS__は、そのコードが「どのクラスに書かれているか」を表すものであり、実際に実行されているインスタンスのクラス名(サブクラス)とは異なる場合があります。実行時のクラス名が必要な場合はstatic::classやget_class($this)を使いましょう(例3・例6を参照)。 self::classとの違いはほぼない PHP 5.5以降で使えるself::classは、__CLASS__とほぼ同じ値を返します。新しいコードでは、より統一感のあるself::classの記法が好まれる傾向にありますが、どちらを使っても機能的な違いはほとんどありません。- グローバルスコープでは空文字列になる クラス定義の外側(通常の関数やスクリプトのトップレベル)で
__CLASS__を使うと、空文字列が返ります。 - トレイト内では「使用しているクラス」の名前になる トレイトはそれ自体が独立してインスタンス化されることはないため、トレイト内に書かれた
__CLASS__は、そのトレイトをuseしているクラスの名前を返します(例5を参照)。これは直感に反すると感じる人もいるため、押さえておくべき挙動です。 - 名前空間を含む完全修飾名が返ることを前提に処理する 名前空間を使っているプロジェクトでは、
__CLASS__はApp\Models\Userのような完全修飾名を返します。クラス名の「短い部分」だけが欲しい場合は、basename(str_replace('\\', '/', __CLASS__))のような追加処理や、(new \ReflectionClass(__CLASS__))->getShortName()を使う必要があります。
まとめ
| 観点 | まとめ |
|---|---|
| 何をする定数か | それが記述されているクラスの名前(名前空間込みの完全修飾名)に置き換わる |
| 主な用途 | エラーメッセージへのクラス名埋め込み、ロギング、トレイト内での呼び出し元クラスの特定 |
| 継承時の挙動 | 常に「定義元」のクラス名を返す(実行時の実際のクラスとは異なる場合がある) |
| 動的な代替 | 実行時のクラス名が必要な場合はstatic::classやget_class($this)を使う |
| 注意点 | 継承時の静的な値であること、トレイト内での挙動、グローバルスコープでは空文字列になること |
__CLASS__ は、コードが「定義された」時点でのクラス名を静的に取得するためのマジック定数です。継承関係において実行時の動的なクラス名が必要な場面では、遅延静的束縛を使った static::class との使い分けを正しく理解することが、意図通りに動作するコードを書く上で重要です。
