PHP 8.4 中 foreach 默认仍不修改原数组值,因 $v 是值拷贝;需用键值赋值、引用遍历(后加 unset)或 array_walk 才生效。
PHP 8.4 中 foreach 修改数组值**默认仍然无效**——这不是新 bug,而是延续了 PHP 自 5.0+ 以来的语义:遍历时对变量的赋值操作作用于副本,除非显式使用引用。
foreach ($arr as $v) { $v = ...; } 不生效因为 $v 是当前元素的**值拷贝**(非引用),修改它只改变临时变量,不影响原数组。即使在 PHP 8.4,该行为未被更改,官方明确将其视为“预期行为”而非缺陷。
$v = new StdClass() 仍会断开与原数组项的关联foreach 的只读模式(foreach ($arr as readonly $v)),但默认仍是可写副本,不自动启用引用&$arr[0]),$v 会继承该引用关系,但这是特例,不是通用解法必须让循环变量指向原数组内存位置。以下方法在 PHP 8.4 完全有效:
foreach ($arr as $k => $v) { $arr[$k] = strtoupper($v); } —— 最安全,兼容所有版本,无引用风险foreach ($arr as &$v) { $v = strtoupper($v); } unset($v); —— 注意末尾 unset($v),否则 $v 会持续引用最后一个元素,导致后续意外修改array_walk 或 array_map:array_walk($arr, function(&$item) { $item = strtoupper($item); }); —— 函数内天然支持引用参数,无需手动 unset
特别注意:只读 foreach 会报错如果你误用了新语法 foreach ($arr as readonly $v),再尝试修改 $v,PHP 8.4 会抛出 Fatal error: Cannot modify readonly variable。这不是“失效”,而是主动阻止错误操作。
立即学习“PHP免费学习笔记(深入)”;
readonly,改用上述三种可写方案& 却试图修改的 foreach 给出警告,但运行时不会拦截foreach ($arr as &$v) {
$v = trim($v);
}
unset($v); // 这一行不能省!PHP 8.4 不会自动清理循环变量引用
最易被忽略的是引用遍历后忘记 unset($v)。PHP 8.4 没有放宽这个要求,反而因更严格的引用跟踪让这类 bug 更容易暴露——比如后续代码中 $v = 'new'; 会意外改掉原数组最后一项。