魔術常數是 PHP 預定義常數,其值隨代碼位置動態變化,不區分大小寫。共八個,提供除錯、日誌、路徑解析、反射等關鍵資訊。本文詳細解析各常數行為與實務應用。
| 常數 | 說明 | 回傳型別 | PHP 版本 |
|---|---|---|---|
__LINE__ | 當前行號 | int | 所有 |
__FILE__ | 完整檔案路徑(已解析符號連結) | string | 所有 |
__DIR__ | 檔案所在目錄(等同 dirname(__FILE__)) | string | 5.3.0+ |
__FUNCTION__ | 函數名稱(區分大小寫,PHP 5+) | string | 4.3.0+ |
__CLASS__ | 類別名稱(含命名空間,區分大小寫,PHP 5+) | string | 4.3.0+ |
__TRAIT__ | Trait 名稱(含命名空間) | string | 5.4.0+ |
__METHOD__ | 類別方法名稱(含類別名,區分大小寫) | string | 5.0.0+ |
__NAMESPACE__ | 當前命名空間名稱(區分大小寫) | string | 5.3.0+ |
<?php
echo "這是第 " . __LINE__ . " 行\n"; // 輸出行號
// 多行字串中以起始行為準
$str = "第 " . __LINE__ . " 行開始
第 " . __LINE__ . " 行結束";
?>
<?php
echo __FILE__;
// /var/www/html/project/src/Controller/UserController.php
// 包含檔案中返回被包含檔案路徑
// main.php: require 'config.php';
// config.php: echo __FILE__; // 顯示 config.php 路徑
<?php
echo __DIR__;
// /var/www/html/project/src/Controller
// 專案根目錄常用模式
define('ROOT_PATH', __DIR__ . '/../../');
// 或 PHP 7.0+
define('ROOT_PATH', dirname(__DIR__, 2));
<?php
function processOrder() {
echo __FUNCTION__; // "processOrder"
}
class OrderService {
public function process() {
echo __FUNCTION__; // "process" (不含類別名)
}
}
// 閉包
$fn = function() { echo __FUNCTION__; }; // "{closure}"
$fn();
<?php
namespace App\Models;
class User {
public function getClass() {
return __CLASS__; // "App\Models\User"
}
public static function getClassStatic() {
return __CLASS__; // "App\Models\User"
}
}
$user = new User();
echo $user->getClass();
echo User::getClassStatic();
// Trait 中使用
trait Loggable {
public function log() {
echo __CLASS__; // 使用此 Trait 的類別名
}
}
class Article {
use Loggable;
}
$article = new Article();
$article->log(); // "Article" (而非 Loggable)
<?php
trait Timestampable {
public function getTraitName() {
return __TRAIT__; // "Timestampable"
}
}
class Model {
use Timestampable;
}
$model = new Model();
echo $model->getTraitName(); // "Timestampable"
// 命名空間下
namespace App\Traits;
trait SoftDeletes {
public function traitName() { return __TRAIT__; } // "App\Traits\SoftDeletes"
}
<?php
class UserService {
public function create() {
echo __METHOD__; // "UserService::create"
}
public static function find() {
echo __METHOD__; // "UserService::find"
}
}
echo __METHOD__; // 全域空間顯示為空字串或函數名
<?php
namespace App\Http\Controllers;
echo __NAMESPACE__; // "App\Http\Controllers"
// 動態建構類別名
function makeModel(string $model): string {
return __NAMESPACE__ . '\\Models\\' . $model;
}
// App\Http\Controllers\Models\User
<?php
function debugLog(string $message, array $context = []): void {
$log = sprintf(
"[%s] %s:%d %s() - %s",
date('c'),
basename(__FILE__),
__LINE__,
__FUNCTION__,
$message
);
error_log($log . ' ' . json_encode($context, JSON_UNESCAPED_UNICODE));
}
debugLog('用戶登入', ['user_id' => 123, 'ip' => $_SERVER['REMOTE_ADDR']]);
// [2024-01-15T10:30:00+08:00] AuthController.php:45 login() - 用戶登入 {"user_id":123,"ip":"192.168.1.1"}
<?php
// 在 Composer vendor/autoload.php 或自訂載入器中
$baseDir = __DIR__ . '/../src/'; // 專案 src 目錄
<?php
// config.php 在專案根目錄
require_once __DIR__ . '/../config/database.php';
// 避免使用相對路徑 require '../config.php'(依賴當前工作目錄)
<?php
namespace App\Factories;
function createController(string $name): object {
$class = __NAMESPACE__ . '\\..\\Controllers\\' . $name . 'Controller';
if (!class_exists($class)) {
throw new InvalidArgumentException("Controller $name 不存在");
}
return new $class();
}
<?php
trait A { public function test() { echo __TRAIT__ . "::test\n"; } }
trait B { public function test() { echo __TRAIT__ . "::test\n"; } }
class C {
use A, B {
A::test insteadof B;
B::test as testB;
}
}
$c = new C();
$c->test(); // A::test
$c->testB(); // B::test
| 誤區 | 正確認知 |
|---|---|
| __FILE__ 在 include 中回傳主檔案路徑 | 回傳被包含檔案路徑 |
| __DIR__ 結尾有斜線 | 無斜線(根目錄除外) |
| __FUNCTION__ 含類別名 | 僅函數/方法名,__METHOD__ 含類別 |
| __CLASS__ 在 Trait 中回傳 Trait 名 | 回傳使用 Trait 的類別名 |
| 魔術常數可像變數一樣賦值 | 為常數,不可修改 |
| 命名空間外 __NAMESPACE__ 為 null | 為空字串 "" |
__DIR__ 優於 dirname(__FILE__)(語意更清晰、效能相同)魔術常數是 PHP 反射與元編程的基礎工具。熟練掌握其行為差異,能撰寫更健壯的載入器、除錯工具、日誌系統與動態架構元件。