PHP中static变量仅在单次请求内同函数多次调用间有效,不跨请求、不跨并发、不跨递归层级;类中不可声明static变量,须用类静态属性;递归时必然状态污染,应显式传参替代。

PHP 7.0 中 static 变量只能在单次函数调用链内保持状态,无法跨请求、跨并发、跨递归层级“可靠共享”——它只在当前请求的同一函数多次调用间有效,且极易被递归或并发踩坑。
函数内 static $var = ... 只在同函数多次调用时生效
这是唯一合法且行为可预测的用法。static 初始化表达式(如 static $cache = json_decode(file_get_contents('config.json')))仅执行一次,后续调用复用该值。
- 必须写在函数体最外层,不能包在
if或for里(语法虽可能通过,但行为未定义) - PHP 8.3+ 对初始化做了编译期优化,若含
time()等运行时值,首次调用前uopz_get_static()可能返回null - 它不解决递归污染问题:递归调用同一函数时,所有层级共用同一个
$var,上层返回前值已被下层改写
类方法里写 static $x 是语法错误
PHP 不允许在方法体内声明静态变量,public function foo() { static $x = 0; } 直接报 Parse error。
- 想在类中维持状态,必须声明为类的静态属性:
private static $counter = 0; - 方法内访问要用
self::$counter或static::$counter,不能用$this-> -
self::绑定定义处类名,static::绑定实际调用者类名——继承场景下二者行为不同,选错会导致子类状态意外共享
递归调用时 static 状态必然污染
这是最常被误用的场景。例如树遍历中用 static $path = [] 记录路径,结果多层递归互相覆盖、并发请求交叉写入、不同根节点调用相互干扰。
立即学习“PHP免费学习笔记(深入)”;
- 根本原因:
static生命周期绑定函数定义,不随调用栈隔离 - 正确替代方案:所有状态必须作为参数显式传递,如
traverse($node, $path, $depth) - 路径拼接用
array_merge($path, [$node['id']]),避免array_push($path, ...)原地修改导致下层误用 - 深度限制检查放在递归开头:
if ($depth > 100) return;,比结尾判断更早止损
动态调用静态方法时 static 属性仍属类级别
像 $class = 'User'; $method = 'find'; $data = $class::$method(); 这种写法没问题,但注意:其中访问的 self::$cache 或 static::$cache 仍是整个类的静态属性,不是“这次调用专属”的。
- 如果
User::find()内部用了self::$cache,那所有对User::find()的调用都共享这个缓存 - 若需调用间隔离,必须把缓存逻辑移到参数里,或用
SplObjectStorage按输入参数哈希键存储 - 别指望
static能模拟 Python 的contextvars——PHP 没这机制,唯一靠谱路径是把上下文“摊平”为参数
真正难处理的从来不是语法怎么写,而是误以为 static 能跨调用栈、跨请求、跨协程保持独立状态。它只活在单次 FPM worker 请求周期里,且完全不感知调用层次——这点一旦忽略,debug 成本远高于多传两个参数。



















