php函数内static变量仅首次调用时初始化,后续调用保留值;作用域限于函数内,生命周期跨多次调用但不跨请求;不可用函数调用或数组直接初始化,需配合null判断实现单次初始化逻辑。

static变量在函数内只初始化一次
PHP里函数内的static变量不是每次调用都重置,而是首次执行时初始化,之后调用保留上次的值。这和全局变量不同——它作用域仍局限在函数内部,外部不可见,但生命周期跨多次调用。
常见错误现象:static $count = 0;写在函数里,结果发现第二次调用时$cnt没从0开始,反而累加了——这不是bug,是预期行为。
- 初始化只发生在第一次进入函数时,后续
static $x = time();里的time()不会重复执行 - 不能用表达式直接初始化(如
static $arr = [1,2];会报错),PHP 5.6+才支持标量表达式,数组/对象仍需在函数体内赋值 - 若初始化值是函数调用(如
static $db = new PDO(...);),PHP会拒绝,必须拆成声明+判断赋值
如何正确实现“首次加载”逻辑
很多场景想“只做一次初始化”,比如连接数据库、读配置文件、生成唯一ID种子。靠static加条件判断是最轻量的做法,比单例或全局状态更可控。
使用场景:工具函数中缓存计算结果、避免重复加载大文件、防止重复注册钩子。
立即学习“PHP免费学习笔记(深入)”;
典型写法:
function get_config() {
static $config = null;
if ($config === null) {
$config = json_decode(file_get_contents('/path/to/config.json'), true);
}
return $config;
}
- 别写
static $config = json_decode(...);——语法错误,PHP不允许函数调用作static默认值 - 用
=== null判断,而不是!$config,避免配置里有0/false等falsy值被误判 - 注意并发安全:PHP-FPM每个请求是独立进程,static变量天然隔离;但如果是常驻进程(如Swoole),需额外考虑协程/worker间共享问题
static函数与普通函数调用开销差异
函数本身声明为static(即static function foo())和函数内部用static变量完全无关。前者是类中静态方法,后者是函数作用域内的静态变量——名字一样,机制完全不同,混用容易误解。
性能影响几乎可忽略:static变量存储在函数的编译器符号表中,访问速度和局部变量基本一致;没有反射或动态查找开销。
- 不要因为“static听起来高级”就滥用,能用普通变量解决的,别硬套static
- static变量无法被unset()销毁(
unset($var)对static无效),只能靠脚本结束自动清理 - 调试时var_dump()能看到static变量的当前值,但IDE断点可能不显示其历史变化,得靠日志辅助观察
容易被忽略的生命周期边界
static变量的“持久性”仅限于单个请求周期。PHP脚本跑完,所有static变量就清空了——它不是跨请求的,也不是跨进程的。很多人误以为它能替代Redis或APCu缓存,结果上线后发现数据根本没留到下次请求。
真实限制:
- FPM模式下:每个请求都是新进程,static变量彼此完全隔离
- CLI模式下:一个脚本多次调用同一函数,static才真正体现“跨调用”效果
- 如果用了OpCache,函数opcode被缓存,但static变量值依然每次请求重新初始化(OpCache不缓存运行时数据)
复杂点在于:当逻辑嵌套深、函数被匿名函数闭包引用、或结合Generator使用时,static变量的行为会变得隐晦——这时候不如明确定义一个类属性来管理状态,可读性和可测性更高。











