unset() 只从当前作用域符号表移除变量名,不直接释放内存;访问已 unset 变量会报 notice: undefined variable,写入则创建新变量;zval 是否回收取决于引用计数与 gc。

不能直接用了,访问会报 Notice: Undefined variable,但“删没删干净”得看变量类型、引用关系和作用域——unset() 不是清内存,只是把变量名从当前作用域的符号表里摘掉。
unset() 后访问变量会怎样
执行 unset($var) 后,该变量在当前作用域彻底“消失”:再次读取 $var 会触发 Notice: Undefined variable;写入会自动创建新变量(非严格模式下),但这是个全新变量,跟原来的无关。
- 注意:PHP 8.0+ 对未定义变量读取默认开启
E_NOTICE,线上环境通常已开启,所以不是“静默失败”,而是明确报错 - 用
isset($var)或array_key_exists('var', $GLOBALS)检查,结果都是false - 但
get_defined_vars()也查不到它——说明符号表条目真没了
为什么有时候 unset() 后值还能“被看到”
常见错觉来源:变量值(zval)没被回收,不代表变量还“活着”。比如:
-
$a = ['x' => 1]; $b = $a; unset($a);→$b仍可访问原数组,因为 zval 的引用计数是 2,unset($a)只减到 1,没到 0 -
$res = fopen('file.txt', 'r'); unset($res);→ 文件句柄立即关闭,这是资源类型的特例,和其他变量行为不同 - 静态变量、闭包
use、对象属性、全局数组元素(如$_SESSION['user'])被unset()后,原始数据可能还在其他地方挂着
foreach 中 unset() 数组键的坑
边遍历边删键,极易漏项或触发 Warning: Undefined array key(PHP 8.0+):
- 错误写法:
foreach ($arr as $k => $v) { if ($v === 'target') unset($arr[$k]); } - 问题:内部数组指针不重排,
foreach仍按原始顺序推进,删掉第 1 个后,原第 2 个键可能被跳过 - 安全做法:先收集键名,再统一删:
$to_remove = []; foreach ($arr as $k => $v) { if ($v === 'target') $to_remove[] = $k; } foreach ($to_remove as $k) unset($arr[$k]);,或直接用$arr = array_filter($arr, fn($v) => $v !== 'target');
超全局变量和 $GLOBALS 不能靠 unset() 真删
unset($_GET['id']) 或 unset($GLOBALS['foo']) 看似成功,实际只断开了当前作用域的引用:
-
$_GET是请求快照 + 引用结构,删了键不影响原始数据,后续 include 的脚本或框架中间件仍能读到 -
$GLOBALS['foo']被 unset,但若函数内声明过global $foo,那个$foo依然可用 - 真正要清理 session 数据,该用
$_SESSION = [];或session_unset();,而不是对$_SESSION本身unset()
最易被忽略的一点:你以为 unset() 释放了内存,其实只是解绑;真正回收依赖引用计数归零 + GC 触发时机。大对象处理完后,如果内存没降,别急着怀疑 unset() 失效,先用 xdebug_debug_zval('var_name') 看 refcount 和 is_ref,再考虑是否要手动 gc_collect_cycles()。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











