php变量在单次http请求或cli脚本结束时彻底销毁,函数局部变量执行完即释放,静态变量和全局变量也仅存活至请求终止,不存在跨请求持久化。

PHP变量什么时候被销毁
PHP变量的生命周期严格绑定到它的作用域和请求周期——函数内定义的变量在函数执行完立刻释放;全局变量或类属性在脚本执行结束时才清理;而所有变量(无论在哪定义)都会在单次HTTP请求或CLI脚本运行结束后彻底消失。
这意味着:没有“跨请求持久化”的变量,$_SESSION 或 $_COOKIE 看似延续,其实靠的是服务端存储+客户端传参,不是变量本身活过了请求。
- 函数局部变量:进入函数时分配,
return或异常退出后立即销毁(包括引用计数归零) - 静态变量:
static $x在首次声明时初始化,后续调用保留值,但仍在当前请求结束时释放 - 全局变量:
$GLOBALS里的项、未加global的文件级变量,同样只活到脚本终止 - 对象实例:被所有引用都断开后触发
__destruct(),但绝不跨请求存活
为什么unset()有时没效果
unset() 并不直接“删除内存”,只是断开当前符号与zval的绑定。如果还有其他变量、数组元素、对象属性或闭包使用着同一个zval,它就不会被回收。
常见误判场景:
立即学习“PHP免费学习笔记(深入)”;
- 对数组元素用
unset($arr[0])后,count($arr)减1,但底层zval可能仍被其他变量引用 - 对象属性设为
null不等于销毁:$obj->prop = null只是改值,unset($obj->prop)才移除属性(若非public且有__unset则走魔术方法) - 循环引用对象(A→B→A):即使所有外部引用都被
unset(),PHP 7.4+ 之前需GC介入才能回收,容易造成内存滞留
超全局变量的生命周期特殊在哪
$_GET、$_POST、$_SERVER 这些超全局变量不是“一直存在”,而是PHP在每次请求开始时从SAPI层(如Apache、FPM)读取原始数据后填充的副本。它们和其他变量一样,在脚本结束时释放。
关键点:
- 修改
$_POST不会影响原始HTTP请求体,只是改了PHP内部的数组副本 -
$_SESSION是个例外:它通过session_start()关联到一个会话ID,并在脚本结束时自动调用session_write_close()将数据序列化写入存储(文件/Redis等),所以“看起来”跨请求,实际是读写外部存储 -
$GLOBALS是全局符号表的引用数组,修改其中的值等同于修改对应全局变量,但它本身不延长任何变量寿命
CLI模式下变量生命周期有变化吗
没有本质变化,只是“请求周期”变长了——CLI脚本不依赖HTTP,生命周期就是从启动到exit()或自然结束。长时间运行的CLI脚本(比如守护进程)必须主动管理变量,否则内存只会涨不会降。
典型陷阱:
- 在while循环里不断
$data[] = ...而不重置,数组持续膨胀,zval无法复用 - 使用
pcntl_fork()后,子进程会复制父进程的整个符号表,但之后各自独立,别指望父进程unset()能影响子进程 - 匿名函数捕获变量形成闭包:
function () use ($bigArray) { ... }会让$bigArray在闭包存活期间无法释放,哪怕原作用域已结束
真正决定变量何时不见的,从来不是你写了unset(),而是PHP的引用计数是否归零 + 是否触发了垃圾回收。而所有这些,都在单次执行范围内完成——跨请求?不存在的。











