在配置管理、多環境切換、功能開關、國際化訊息等場景,常需根據變數動態構建常數名稱並取得其值。PHP 提供 constant() 函數完美解決此需求。
<?php
// 定義常數
define('APP_VERSION', '1.2.3');
define('DB_HOST_MASTER', '192.168.1.10');
define('DB_HOST_SLAVE', '192.168.1.11');
define('CACHE_DRIVER_REDIS', 'redis');
define('CACHE_DRIVER_FILE', 'file');
// 靜態存取(常規)
echo APP_VERSION; // 1.2.3
// 動態存取:constant() 函數
$constName = 'APP_VERSION';
echo constant($constName); // 1.2.3
// 變數拼接構建常數名
$env = 'MASTER';
$dbHostConst = 'DB_HOST_' . $env;
echo constant($dbHostConst); // 192.168.1.10
$driver = 'REDIS';
$cacheConst = 'CACHE_DRIVER_' . $driver;
echo constant($cacheConst); // redis
?>
<?php
// 配置常數群組
define('DB_HOST_DEV', 'localhost');
define('DB_NAME_DEV', 'myapp_dev');
define('DB_USER_DEV', 'dev_user');
define('DB_PASS_DEV', 'dev_pass');
define('DB_HOST_PROD', 'db.prod.internal');
define('DB_NAME_PROD', 'myapp_prod');
define('DB_USER_PROD', 'prod_user');
define('DB_PASS_PROD', 'secure_password_123');
define('DB_HOST_TEST', 'db.test.internal');
define('DB_NAME_TEST', 'myapp_test');
define('DB_USER_TEST', 'test_user');
define('DB_PASS_TEST', 'test_pass');
// 當前環境(可從環境變數讀取)
$env = getenv('APP_ENV') ?: 'DEV'; // DEV, PROD, TEST
// 動態獲取配置群組
function getConfigGroup($prefix, $env) {
$config = array();
$suffixes = array('HOST', 'NAME', 'USER', 'PASS');
foreach ($suffixes as $suffix) {
$constName = $prefix . '_' . $suffix . '_' . $env;
if (defined($constName)) {
$key = strtolower($suffix);
$config[$key] = constant($constName);
}
}
return $config;
}
$dbConfig = getConfigGroup('DB', $env);
// $dbConfig = ['host'=>..., 'name'=>..., 'user'=>..., 'pass'=>...]
?>
<?php
// 功能開關常數
define('FEATURE_NEW_DASHBOARD', true);
define('FEATURE_BETA_API', false);
define('FEATURE_DARK_MODE', true);
define('FEATURE_EXPORT_PDF', true);
// 檢查功能是否啟用
function isFeatureEnabled($featureName) {
$constName = 'FEATURE_' . strtoupper($featureName);
return defined($constName) && constant($constName) === true;
}
// 使用
if (isFeatureEnabled('new_dashboard')) {
// 載入新版儀表板
}
if (isFeatureEnabled('export_pdf')) {
// 顯示 PDF 匯出按鈕
}
// 批次檢查
$features = array('new_dashboard', 'beta_api', 'dark_mode', 'export_pdf');
$enabledFeatures = array_filter($features, 'isFeatureEnabled');
?>
<?php
// 錯誤代碼常數
define('ERR_USER_NOT_FOUND', 1001);
define('ERR_PASSWORD_INVALID', 1002);
define('ERR_EMAIL_EXISTS', 1003);
define('ERR_TOKEN_EXPIRED', 1004);
// 訊息常數(多語言)
define('MSG_ERR_USER_NOT_FOUND_ZH_TW', '找不到使用者');
define('MSG_ERR_USER_NOT_FOUND_EN', 'User not found');
define('MSG_ERR_PASSWORD_INVALID_ZH_TW', '密碼錯誤');
define('MSG_ERR_PASSWORD_INVALID_EN', 'Invalid password');
// 獲取錯誤代碼
function getErrorCode($errorKey) {
return constant('ERR_' . strtoupper($errorKey));
}
// 獲取本地化訊息
function getErrorMessage($errorKey, $lang = 'ZH_TW') {
$constName = 'MSG_' . strtoupper($errorKey) . '_' . $lang;
if (defined($constName)) {
return constant($constName);
}
// 回退預設語言
$fallbackConst = 'MSG_' . strtoupper($errorKey) . '_EN';
return defined($fallbackConst) ? constant($fallbackConst) : 'Unknown error';
}
echo getErrorCode('user_not_found'); // 1001
echo getErrorMessage('password_invalid', 'ZH_TW'); // 密碼錯誤
?>
<?php
class AppConfig {
const VERSION = '2.0.0';
const API_V1 = 'v1';
const API_V2 = 'v2';
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 0;
}
// 類別常數動態存取
$version = constant('AppConfig::VERSION'); // 2.0.0
// 實例方法中動態存取
class Service {
public function getApiEndpoint($version) {
$constName = 'AppConfig::API_' . strtoupper($version);
if (defined($constName)) {
return 'https://api.example.com/' . constant($constName);
}
throw new Exception("Unknown API version: {$version}");
}
}
$svc = new Service();
echo $svc->getApiEndpoint('v1'); // https://api.example.com/v1
?>
| 特性 | constant() | define() | 變數變數 $$var |
|---|---|---|---|
| 用途 | 讀取常數值 | 定義常數 | 讀取/寫入變數 |
| 參數 | 常數名稱字串 | 名稱、值 | 變數名稱字串 |
| 作用域 | 全域/類別常數 | 全域/命名空間 | 當前符號表 |
| 常數不存在 | 拋出 Warning,返回 null | 重複定義發 Warning | 建立新變數 |
| 效能 | 極快(內部哈希查找) | 定義時一次 | 快 |
<?php
// ❌ 危險:直接使用用戶輸入構建常數名
// $value = constant('CONFIG_' . $_GET['key']);
// ✅ 安全:白名單驗證
$allowedKeys = array('DB_HOST', 'APP_NAME', 'CACHE_TTL');
$key = $_GET['key'] ?? '';
if (in_array($key, $allowedKeys)) {
$constName = 'CONFIG_' . $key;
if (defined($constName)) {
$value = constant($constName);
}
}
?>
<?php
// 推薦:群組前綴 + 大寫下劃線
define('APP_DEBUG', true);
define('DB_MASTER_HOST', '...');
define('CACHE_REDIS_TTL', 3600);
define('API_THIRD_PARTY_TIMEOUT', 5);
// 避免:無前綴、混合大小寫、過於通用名稱
// define('HOST', '...'); // 衝突風險高
// define('Config_Db_Host', '...'); // 不符合慣例
?>
<?php
/**
* 安全獲取常數值,不存在返回預設值
*/
function getConstant($name, $default = null) {
return defined($name) ? constant($name) : $default;
}
/**
* 批次獲取常數群組
*/
function getConstantsByPrefix($prefix) {
$result = array();
$allConstants = get_defined_constants(true);
$scope = $allConstants['user'] ?? array(); // 用戶定義常數
foreach ($scope as $name => $value) {
if (strpos($name, $prefix) === 0) {
$result[$name] = $value;
}
}
return $result;
}
// 使用
$dbConfig = getConstantsByPrefix('DB_');
?>
constant() 內部為哈希表查找,時間複雜度 O(1),極快defined() 結果或直接快取常數值constant() 是 PHP 動態存取常數的標準途徑,配合命名規範與白名單驗證,能構建靈活、安全的配置管理、功能開關、國際化等系統。掌握其與 define()、變數變數的區別,避免濫用導致程式碼難以靜態分析,將動態性限制在明確的邊界內(如環境配置載入、功能旗標檢查),是高質量 PHP 代碼的關鍵特徵。