PHP 类常量
概述
类常量(Class Constants)是在类中定义的不可变值。与属性不同,常量一旦定义就不能修改。类常量为每个类分配一次,而非每个实例。
版本要求
- PHP 7.1+:常量支持访问修饰符
- PHP 8.1+:支持
final常量 - PHP 8.3+:支持类型化类常量、动态获取常量、严格的接口可见性检查
基础概念
基本声明
使用 const 关键字声明类常量,默认可见性为 public。
php
<?php
declare(strict_types=1);
class HttpStatusCode
{
public const OK = 200;
public const NOT_FOUND = 404;
public const INTERNAL_ERROR = 500;
}
echo HttpStatusCode::OK; // 200访问方式
类常量通过 ::(范围解析操作符)访问,支持多种方式。
php
<?php
declare(strict_types=1);
class MyClass
{
public const CONSTANT = 'constant value';
public function showConstant(): void
{
echo self::CONSTANT . "\n";
}
}
// 类外部使用 ClassName::
echo MyClass::CONSTANT . "\n";
// 通过变量动态调用
$className = 'MyClass';
echo $className::CONSTANT . "\n";
// 通过对象实例
$obj = new MyClass();
echo $obj::CONSTANT . "\n";
$obj->showConstant();语法与代码
访问修饰符(PHP 7.1+)
类常量支持 public、protected、private 修饰符。
php
<?php
declare(strict_types=1);
class ApiConfig
{
public const API_VERSION = 'v2';
protected const MAX_RETRIES = 3;
private const API_KEY = 'secret-key-123';
public function getRetries(): int
{
return self::MAX_RETRIES;
}
public function getKey(): string
{
return self::API_KEY;
}
}
$config = new ApiConfig();
echo ApiConfig::API_VERSION; // v2
echo $config->getRetries(); // 3
// Error: Cannot access protected/private const
// echo ApiConfig::MAX_RETRIES;final 常量(PHP 8.1+)
final 常量不能被子类重新定义。
php
<?php
declare(strict_types=1);
class BaseService
{
final public const VERSION = '1.0';
public const TIMEOUT = 30;
}
class UserService extends BaseService
{
// Error: Cannot override final constant
// public const VERSION = '2.0';
public const TIMEOUT = 60; // 非 final 常量可以覆盖
}
echo UserService::TIMEOUT; // 60类型化类常量(PHP 8.3+)
类常量可指定标量类型或数组类型,数组内容只能包含标量类型。
php
<?php
declare(strict_types=1);
class ServerConfig
{
public const bool DEBUG = false;
public const int PORT = 8080;
public const float VERSION = 2.1;
public const string HOST = 'localhost';
public const array ALLOWED_IPS = ['127.0.0.1', '::1'];
}
var_dump(ServerConfig::DEBUG); // bool(false)
var_dump(ServerConfig::PORT); // int(8080)
var_dump(ServerConfig::VERSION); // float(2.1)
var_dump(ServerConfig::HOST); // string(8) "localhost"动态获取常量(PHP 8.3+)
使用变量名动态获取类常量。
php
<?php
declare(strict_types=1);
class Status
{
public const PENDING = 'pending';
public const ACTIVE = 'active';
public const ARCHIVED = 'archived';
}
$name = 'ACTIVE';
echo Status::{$name}; // active常量表达式
常量值可以是常量表达式,包括其他常量、数学运算等。
php
<?php
declare(strict_types=1);
class MathConstants
{
public const PI = 3.14159;
public const TAU = self::PI * 2;
public const MAX_VALUE = 100;
public const MIN_VALUE = 0;
public const RANGE = self::MAX_VALUE - self::MIN_VALUE;
}详细说明
接口中的常量可见性(PHP 8.3+)
PHP 8.3 起严格检查接口与实现类中常量的可见性一致性。
php
<?php
declare(strict_types=1);
interface CacheInterface
{
public const DEFAULT_TTL = 3600;
}
class RedisCache implements CacheInterface
{
// PHP 8.3+ Fatal error: 可见性必须为 public
// protected const DEFAULT_TTL = 7200;
public const DEFAULT_TTL = 7200; // 正确:保持 public
}类常量 vs 静态属性
| 特性 | 类常量 | 静态属性 |
|---|---|---|
| 关键字 | const | static |
| 可变性 | 不可变 | 可变 |
| 默认值 | 常量表达式 | 常量表达式 |
| 类型声明 | PHP 8.3+ | PHP 7.4+ |
| 继承 | 可覆盖(除非 final) | 可覆盖 |
| 适用场景 | 配置、状态码 | 计数器、缓存 |
实战示例
状态机模式
php
<?php
declare(strict_types=1);
class OrderStatus
{
public const PENDING = 'pending';
public const PAID = 'paid';
public const SHIPPED = 'shipped';
public const DELIVERED = 'delivered';
public const CANCELLED = 'cancelled';
public const array TRANSITIONS = [
self::PENDING => [self::PAID, self::CANCELLED],
self::PAID => [self::SHIPPED, self::CANCELLED],
self::SHIPPED => [self::DELIVERED],
self::DELIVERED => [],
self::CANCELLED => [],
];
public static function canTransition(string $from, string $to): bool
{
return in_array($to, self::TRANSITIONS[$from] ?? [], true);
}
}
var_dump(OrderStatus::canTransition('pending', 'paid')); // true
var_dump(OrderStatus::canTransition('pending', 'shipped')); // false注意事项
- 常量名建议全大写:遵循
UPPER_SNAKE_CASE命名规范 - 接口常量自动为 public:不能声明为 private 或 protected
- PHP 8.3 可见性检查更严格:实现接口时必须保持常量可见性一致
- self:: vs static:::
self::引用定义时的类,static::引用运行时的类
最佳实践
- 配置值用常量:如超时时间、最大重试次数、API 版本等
- 状态码/枚举值用常量:避免魔术字符串/数字
- final 常量防止覆盖:对关键常量使用
final修饰 - PHP 8.3+ 使用类型化常量:获得额外的类型安全保障
进阶用法
调试与测试技巧
php
<?php
declare(strict_types=1);
// 单元测试辅助函数
function createTestResource(): mixed
{
return match (true) {
default => new stdClass(),
};
}
// 调试输出函数
function debugOutput(mixed , string = ''): void
{
= ? ": " : '';
.= print_r(, true);
fwrite(STDERR, . "\n");
}
// 性能基准测试
function benchmark(callable , int = 1000): float
{
= hrtime(true);
for ($i = 0; $i < $iterations; $i++) {
$fn();
}
return (hrtime(true) - $start) / 1e9;
}日志记录实践
php
<?php
declare(strict_types=1);
/**
* 简易日志记录器
*/
class SimpleLogger
{
private string $logFile;
private string $level = 'INFO';
public function __construct(string $logFile)
{
$this->logFile = $logFile;
}
public function info(string $message, array $context = []): void
{
$this->log('INFO', $message, $context);
}
public function warning(string $message, array $context = []): void
{
$this->log('WARNING', $message, $context);
}
public function error(string $message, array $context = []): void
{
$this->log('ERROR', $message, $context);
}
private function log(string $level, string $message, array $context): void
{
$timestamp = date('Y-m-d H:i:s');
$contextStr = $context ? ' ' . json_encode($context, JSON_UNESCAPED_UNICODE) : '';
$line = "[{$timestamp}] [{$level}] {$message}{$contextStr}\n";
file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
}
}配置与环境检测
php
<?php
declare(strict_types=1);
// 环境检测工具
class EnvironmentChecker
{
public static function checkRequirements(array $requirements): array
{
$results = [];
foreach ($requirements as $name => $check) {
$results[$name] = is_callable($check) ? $check() : false;
}
return $results;
}
public static function getSystemInfo(): array
{
return [
'php_version' => PHP_VERSION,
'os' => PHP_OS,
'sapi' => PHP_SAPI,
'memory_limit' => ini_get('memory_limit'),
'max_execution_time' => ini_get('max_execution_time'),
'loaded_extensions' => get_loaded_extensions(),
];
}
}常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 连接超时 | 网络问题/配置错误 | 检查配置,增加超时时间 |
| 权限不足 | 文件/目录权限 | 使用 chmod/chown 修正 |
| 性能下降 | 索引缺失/数据量大 | 添加索引,优化查询 |
| 数据不一致 | 并发冲突/事务残留 | 使用锁机制和事务 |
| 内存溢出 | 大数据集/未释放资源 | 增大内存限制,分批处理 |
故障排除步骤
- 检查错误日志和异常信息
- 确认配置和环境是否正确
- 使用调试工具逐步排查
- 参考官方文档查找已知问题
版本兼容性说明
| 功能 | 最低版本 | 说明 |
|---|---|---|
| 基础功能 | PHP 8.1 | 本文档基准版本 |
| 只读属性 | PHP 8.1 | public readonly 修饰符 |
| 枚举类型 | PHP 8.1 | enum 类型和 match 表达式 |
| Fiber | PHP 8.1 | 协程/轻量级并发 |
| 命名参数 | PHP 8.0 | foo(arg_name: value) |
| 联合类型 | PHP 8.0 | `int |
| Null 安全运算符 | PHP 8.0 | $obj?->method() |
| 析构器 promotion | PHP 8.0 | __construct(public $x) |
php
<?php
declare(strict_types=1);
// 版本兼容性检测
function ensureVersion(string $minVersion): void
{
if (version_compare(PHP_VERSION, $minVersion, '<')) {
throw new RuntimeException(
sprintf('需要 PHP %s+, 当前版本: %s', $minVersion, PHP_VERSION)
);
}
}
ensureVersion('8.1.0');