PHP 8.4 扩展常量表达式支持:允许编译期静态求值的复杂表达式(如算术、数组合并、类型转换)、类常量支持类型声明与 readonly、define() 支持命名空间及动态作用域,但禁用用户函数、对象操作及非纯内置函数。

常量表达式现在支持更多运行时不可变结构
PHP 8.4 允许在 const、define() 和类常量定义中使用更复杂的表达式,只要它们在编译期能被静态求值。此前(如 PHP 8.3)只允许字面量、已知常量、简单算术和数组字面量;PHP 8.4 新增支持:
const MAX_RETRY = 3 * 2;
const FEATURES = ['log' => true, 'cache' => false] + ['metrics' => true];
const DEFAULT_TIMEOUT = (int) getenv('DEFAULT_TIMEOUT') ?: 5000;注意:getenv() 调用之所以可行,是因为 PHP 8.4 将其标记为「纯函数」——前提是环境变量在启动时已确定且未被修改。
类常量支持属性类型推导与联合类型声明
PHP 8.4 允许在 const 声明中显式标注类型,并支持联合类型、readonly 修饰符和泛型约束(仅限于静态上下文):
class Config
{
public const int MAX_ITEMS = 100;
public const string|bool DEBUG_MODE = $_ENV['DEBUG'] ?? false;
public readonly const array STATUS_CODES = ['ok' => 200, 'err' => 500];
} 关键点:readonly const 表示该常量值不可被反射或扩展覆盖(即使通过 ReflectionClass::setStaticPropertyValue 也会失败),但不改变其作用域行为。
define() 支持带命名空间的常量名和动态作用域
define() 在 PHP 8.4 中不再局限于全局命名空间或简单标识符。它现在接受完整命名空间路径,并可配合 __NAMESPACE__ 动态构造:
namespace App\Constants;这解决了过去必须用define(NAMESPACE . '\API_VERSION', 'v2.1'); define('App\Constants\IS_PRODUCTION', $_SERVER['APP_ENV'] === 'prod');
const 定义命名空间常量、却无法延迟求值的矛盾。但注意:define() 定义的常量仍不能用于 match 表达式的分支条件(因非编译期常量),而 const 定义的可以。
容易踩的坑:常量表达式不是“任意代码”
虽然表达式能力增强,但以下操作依然非法:
- 调用用户自定义函数(哪怕无副作用)
- 访问对象属性或方法(包括
static::class) - 使用
new、clone、yield或闭包 - 任何可能触发 autoload 的类名解析
ini_get()、function_exists())看似只读,但在 PHP 8.4 中仍未被标记为纯函数,因此不能出现在常量表达式中。遇到 ParseError: Constant expression contains invalid operations 时,优先检查是否误用了这类函数。











