はじめに
これまでの記事で、現在の行番号を取得する __LINE__、現在のファイルパスを取得する __FILE__ と __DIR__ を解説してきました。今回取り上げる __FUNCTION__ は、それらと同じマジック定数の仲間で、現在実行中の関数(またはメソッド)の名前を取得するためのものです。
__FUNCTION__ は、それが記述されている関数またはメソッドの定義そのものの名前に、コンパイル時に置き換えられます。デバッグログに「どの関数から出力されたか」を自動的に記録したい場合や、リフレクションを使わずに手軽に自分自身の名前を取得したい場合に便利な仕組みです。本記事では基本的な使い方から、クラスメソッド内での挙動、__METHOD__ との違いまで詳しく解説します。
定数概要
| 項目 | 内容 |
|---|---|
| 定数名 | __FUNCTION__ |
| 種別 | マジック定数 |
| 値の型 | 文字列(string) |
| 値の内容 | 現在の関数またはメソッドの名前(クラス名は含まない) |
| 対応バージョン | PHP 4.3.0以降 |
| グローバルスコープでの挙動 | 関数の外側で使うと空文字列になる |
| 関連するマジック定数 | __METHOD__(クラス名を含む)、__CLASS__(クラス名のみ) |
__FUNCTION__と__METHOD__の違い(イメージ図)
class OrderService {
public function process() {
echo __FUNCTION__; → "process" (関数名のみ)
echo __METHOD__; → "OrderService::process" (クラス名を含む)
}
}
function standaloneFunction() {
echo __FUNCTION__; → "standaloneFunction"
// グローバル関数には"クラス名::"の部分がそもそも存在しない
}
echo __FUNCTION__; → "" (関数の外側では空文字列)
ポイントは、__FUNCTION__ が常に「関数名のみ」を返し、クラスメソッドであってもクラス名は含まれないという点です。「このメソッドがどのクラスに属しているか」まで知りたい場合は、後述する __METHOD__ を使う必要があります。
実践サンプル7選
例1:基本的な使い方
<?php
function sampleFunction(): void
{
echo '現在の関数名: ' . __FUNCTION__ . PHP_EOL;
}
sampleFunction();
echo 'グローバルスコープでの値: "' . __FUNCTION__ . '"' . PHP_EOL; // 空文字列になる
例2:クラスメソッド内での挙動を確認する
<?php
class Calculator
{
public function add(int $a, int $b): int
{
echo __FUNCTION__ . 'が呼ばれました' . PHP_EOL; // "add"(クラス名は含まれない)
return $a + $b;
}
}
$calc = new Calculator();
echo $calc->add(3, 5) . PHP_EOL;
例3:デバッグログに自動的に関数名を含めるヘルパー
<?php
function debugLog(string $message, string $functionName): void
{
echo "[{$functionName}] {$message}" . PHP_EOL;
}
function processOrder(int $orderId): void
{
debugLog("注文{$orderId}の処理を開始", __FUNCTION__);
// 何らかの処理...
debugLog("注文{$orderId}の処理が完了", __FUNCTION__);
}
processOrder(1001);
例4:再帰関数の中でのトレースログ
<?php
function factorial(int $n, int $depth = 0): int
{
$indent = str_repeat(' ', $depth);
echo "{$indent}{__FUNCTION__}({$n}) を呼び出し中" . PHP_EOL;
if ($n <= 1) {
return 1;
}
return $n * factorial($n - 1, $depth + 1);
}
echo '結果: ' . factorial(4) . PHP_EOL;
例5:未実装メソッドのプレースホルダーとして使う
<?php
abstract class BaseRepository
{
/**
* 未実装のメソッドが呼ばれた際、
* __FUNCTION__を使ってどのメソッドが未実装かを明確に伝える
*/
protected function notImplemented(): never
{
throw new BadMethodCallException(debug_backtrace()[1]['function'] . 'はまだ実装されていません');
}
public function find(int $id): mixed
{
// 子クラスでオーバーライドされることを想定した基底実装
$this->notImplemented();
}
}
class UserRepository extends BaseRepository
{
// find()をまだオーバーライドしていない状態を想定
}
try {
(new UserRepository())->find(1);
} catch (BadMethodCallException $e) {
echo 'エラー: ' . $e->getMessage() . PHP_EOL;
}
例6:パフォーマンス計測の開始・終了ラベルとして使う
<?php
class PerformanceTimer
{
private static array $timers = [];
public static function start(string $label): void
{
self::$timers[$label] = microtime(true);
}
public static function end(string $label): float
{
$elapsed = microtime(true) - (self::$timers[$label] ?? microtime(true));
echo "{$label}: " . round($elapsed * 1000, 2) . 'ms' . PHP_EOL;
return $elapsed;
}
}
function heavyComputation(): void
{
PerformanceTimer::start(__FUNCTION__);
usleep(50000); // 重い処理のシミュレーション
PerformanceTimer::end(__FUNCTION__);
}
heavyComputation();
例7:クロージャ内での__FUNCTION__の挙動を確認するデモ
<?php
function outerWithClosure(): void
{
echo '外側の関数: ' . __FUNCTION__ . PHP_EOL;
$closure = function () {
// クロージャ自体は名前を持たないため、"{closure}"のような値になる
echo 'クロージャ内: ' . __FUNCTION__ . PHP_EOL;
};
$closure();
}
outerWithClosure();
関連機能との比較
| 機能 | 役割 | __FUNCTION__との違い |
|---|---|---|
__FUNCTION__ | 現在の関数・メソッド名を取得 | 本記事の対象。クラス名は含まれない |
__METHOD__ | 現在のメソッド名を「クラス名::メソッド名」形式で取得 | クラスメソッド内で使うと、クラス名も含めて取得できる |
__CLASS__ | 現在のクラス名のみを取得 | 関数名ではなく、クラス名のみの情報を提供する |
debug_backtrace() | 呼び出し履歴(スタックトレース)を取得 | __FUNCTION__とは異なり、呼び出し元の関数名も動的に取得できる |
(new ReflectionFunction(...))->getName() | リフレクションAPIで関数名を取得 | より高機能だが、__FUNCTION__よりも記述量が多くオーバーヘッドもある |
よくある落とし穴(注意点)
- クラスメソッド内でもクラス名は含まれない
__FUNCTION__は常に関数・メソッド名のみを返します。「どのクラスのメソッドか」まで知りたい場合、__METHOD__を使う必要があります(例2を参照)。この点は非常によくある誤解です。 - グローバルスコープでは空文字列になる 関数やメソッドの外側(スクリプトのトップレベル)で
__FUNCTION__を使うと、空文字列が返ります。関数の中でのみ意味を持つ定数であることを理解しておきましょう。 - クロージャや無名関数では特殊な値になる クロージャの内部で
__FUNCTION__を使うと、"{closure}"のような、人間が読みにくい特殊な文字列が返ることがあります。クロージャの識別が必要な場合は、別の方法(変数名での管理など)を検討しましょう(例7を参照)。 - 呼び出し元の関数名は取得できない
__FUNCTION__はあくまで「それが記述されている」関数自身の名前を返すものであり、その関数を呼び出した側の関数名を知りたい場合はdebug_backtrace()を使う必要があります。 - 静的メソッド内でも同様の挙動になる
staticメソッド内で__FUNCTION__を使った場合も、クラス名は含まれずメソッド名のみが返されます。静的コンテキストかどうかに関わらず、この挙動は一貫しています。
まとめ
| 観点 | まとめ |
|---|---|
| 何をする定数か | それが記述されている関数・メソッドの名前に置き換わる(クラス名は含まない) |
| 主な用途 | デバッグログへの関数名の自動記録、再帰関数のトレース、パフォーマンス計測のラベル |
| クラスメソッドでの挙動 | クラス名は含まれず、メソッド名のみを返す |
| 関連するマジック定数 | __METHOD__(クラス名を含む)、__CLASS__(クラス名のみ) |
| 注意点 | グローバルスコープでは空文字列、クロージャでは特殊な値、呼び出し元の関数名は取得不可 |
__FUNCTION__ は、現在実行中の関数やメソッドの名前を手軽に取得できる、デバッグやログ出力において実用的なマジック定数です。クラス名まで含めた完全な情報が必要な場合は __METHOD__ を使うという使い分けを意識し、適切な場面で活用していきましょう。
