PHP默认按值传递,函数内修改参数不影响外部变量;要修改原变量必须定义和调用时都加&实现引用传递,对象因句柄机制“类似引用”但本质不同。

PHP函数里改不了变量值?默认就是值传递——你传进去的是变量内容的一份拷贝,函数内部怎么改,都不会影响外面的 $a。这不是bug,是语言设计。
为什么函数内修改参数,外部变量没变?
因为PHP默认按值传递:调用时复制一份值给形参,函数体里操作的是副本。原始变量和副本各自独立,互不影响。
-
int、string、bool、float严格值语义,改了形参,实参纹丝不动 -
array在 PHP 7+ 同样是值传递,虽有写时复制(copy-on-write)优化,但行为仍是“改不着外面” - 对象(如
stdClass实例)是个特例:传的是句柄副本,所以改属性会生效,但重赋值(比如$obj = new StdClass())不会影响外部变量
想让函数修改外部变量,必须用引用传递
只有当你明确需要函数直接更新调用处的变量本身(不只是它的内容),才加 &。而且定义和调用两个地方都得加,缺一不可。
- 定义函数时:参数前加
&,例如function updateConfig(&$host) { ... } - 调用时:实参前也必须加
&,例如updateConfig(&$config['host']) - 不能对表达式或字面量取引用,比如
updateConfig(&getHost())或updateConfig(&'localhost')会报Cannot pass parameter by reference - PHP 8.0+ 对运行时引用传递(call-time pass-by-reference)已彻底废弃,只允许在函数定义中声明
&$param,调用时再加&才合法
数组元素能单独传引用吗?语法很关键
可以,但 $arr['key'] 本身不是左值(lvalue),不能直接加 &。PHP 解析器不认这种“动态索引取引用”。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 正确做法:先用变量承接,再传引用:
$item = &$config['database']['host']; updateConfig($item); - ❌ 错误写法:
updateConfig(&$config['cache']['ttl'])→ 直接报错 - 批量处理时用
foreach ($arr as &$v)可以,但循环结束后务必unset($v),否则$v仍绑定到最后一个元素,下次意外修改就来了 - 别直接改
$_POST或$_GET的元素,哪怕语法上可行,也会让数据流变得不可控
对象传参为什么“像引用又不是真引用”?
因为对象变量存的是句柄(handle),不是对象本体。传参复制的是这个句柄,所以两个变量指向同一块内存 —— 改属性生效,换对象不生效。
-
$obj1->name = 'a'; $obj2 = $obj1; $obj2->name = 'b';→$obj1->name变成'b' -
$obj2 = new StdClass();→$obj1完全不受影响 - 若函数内需要替换整个对象(比如工厂返回新实例),仍得用
&$obj引用参数,否则外部变量无法更新 - 要彻底隔离对象,用
clone $obj,注意默认是浅拷贝
最常被忽略的点:引用传递禁用写时复制,对大数组或长字符串可能带来轻微性能开销;而对象的“伪引用”行为,往往让人误以为所有修改都会外溢,其实只限于属性层面。



















