PHP 8.1起,继承的静态方法共享同一static变量,不再各自独立;函数内static变量仍仅初始化一次,但禁止运行时表达式初始化,且生命周期限于单次请求。

PHP 8.1 中 static 变量保持函数内状态的方式和之前版本一致,但关键变化在于「继承方法共享静态变量」——这是最容易被忽略的兼容性断裂点。
static $var = ... 初始化只执行一次
函数内 static 变量在首次执行到该行时初始化,后续调用跳过初始化表达式,直接复用上次值。这点没变,但要注意 PHP 8.1 对初始化表达式的放宽有限:
-
static $x = 42;、static $y = [1, 2];合法(常量表达式) -
static $t = time();、static $d = $_SERVER['REQUEST_TIME'];仍非法——首次调用时会报ParseError或运行时错误 - 哪怕写成
static $flag = true && false;,只要含运行时求值,就禁止
类中 static 方法里的 static 变量行为变了
PHP 8.1 起,子类继承(非重写)父类的静态方法时,该方法内部的 static 变量与父类方法共享同一份存储,不再是各自独立。
class Foo {
public static function counter() {
static $count = 0;
return ++$count;
}
}
class Bar extends Foo {}
Foo::counter(); // 1
Foo::counter(); // 2
Bar::counter(); // 3 ← PHP 8.1+;PHP 8.0 及以前是 1
这个变化让「类级单例缓存」或「跨继承计数」变得自然,但也意味着:
立即学习“PHP免费学习笔记(深入)”;
- 不能再依赖「每个类方法有自己一份 static 变量」做隔离
- 若需隔离,必须显式用类名作键,比如
static $cache[get_called_class()] = []; - 升级前要检查所有继承链上的静态方法是否隐含依赖独立状态
递归或多次调用中 static 变量不会重入初始化
这是最常误用的地方:把 static $done = false; 放在条件分支或循环里,以为每次进分支都会重置,实际它只在函数第一次执行到那行时初始化。
典型陷阱代码:
function process($item) {
if ($item > 10) {
static $log_once = false;
if (!$log_once) {
error_log("Item too big");
$log_once = true;
}
}
// …
}
process(15); // 记 log
process(5); // 不记 log —— 但开发者常以为这里 $log_once 会重置为 false
process(20); // 不再记 log(因为 $log_once 已是 true)
解决办法只有两个:
- 把
static声明提到函数顶部,逻辑上更清晰 - 真需要按参数重置,改用外部传入的引用或缓存数组,例如
static $done = [];+$key = md5(serialize($item));
PHP 8.1 的 static 变量机制本身没改底层生命周期——仍绑定请求周期,不跨请求,也不线程安全。真正要警惕的是继承场景下变量共享这个静默变更,它不报错,但会悄悄改变原有逻辑的执行结果。



















