php变量赋值默认传值,即复制值、内存独立;加&为引用赋值,共享内存;对象赋值是共享实例(非纯引用),需clone隔离;函数参数同理,默认传值,引用需显式声明&。

传值赋值就是复制一份,改一个不影响另一个
PHP 默认所有变量赋值都是传值($b = $a),本质是把 $a 当前的值“拷贝”给 $b,两者内存地址完全独立。哪怕 $a 是数组或对象,只要没用 &,就不是共享同一块内存。
常见错误现象:
— 以为改了 $b 会影响 $a,结果发现毫无反应
— 在函数里修改传进来的数组参数,调用后原数组没变,误以为函数没生效
- 适用场景:需要保留原始数据、做临时计算、避免副作用
- 性能影响:对小变量(int/string)几乎无感;但对大数组或长字符串,PHP 底层其实用了写时复制(COW),真正复制只发生在你第一次修改时——所以别一看到“复制”就慌
- 注意陷阱:
unset($a)不会影响$b;$b = null也不会清空$a
引用赋值用 & 符号,两个变量共用同一块内存
加个 & 就彻底变样:$b = &$a 表示 $b 和 $a 指向完全相同的内存地址。改谁,另一个立刻同步。
常见错误现象:
— 忘记删掉 &,导致后续逻辑意外联动,调试时一头雾水
— 在循环中反复 $ref = &$arr[$i],结果所有 $ref 最终都指向最后一个元素(因为引用被覆盖)
立即学习“PHP免费学习笔记(深入)”;
- 适用场景:需在函数内直接修改外部变量(比如批量处理数组项并原地更新)、实现类似“指针”的效果
- 性能影响:零拷贝,适合超大结构体;但会阻止 COW 机制,一旦有引用存在,PHP 就不敢再优化内存复用
- 关键提醒:
foreach ($arr as &$v)后必须unset($v),否则下次循环可能污染下一个变量
对象默认就是“类引用”,但不是真正的引用赋值
这是最容易混淆的一点:$obj2 = $obj1 看似传值,实际 $obj2 拿到的是对象标识符(handle),指向同一个实例。所以改属性会同步,但重赋值不会:$obj2 = new StdClass() 不会影响 $obj1。
常见错误现象:
— 认为对象赋值是纯引用,结果 $obj2 = null 后 $obj1 还好好的
— 想用 clone $obj1 却忘了写 clone,直接赋值导致状态串扰
- 要真隔离:用
clone $obj1创建独立副本 - 要强制绑定:仍得加
&,比如$ref = &$obj1,这时连对象变量本身都能被替换 - 兼容性注意:PHP 7+ 对象 handle 机制更稳定,但别依赖它做“等价于引用”的判断
函数参数里的传值 vs 传引用,行为和赋值规则一致
函数形参默认也是传值,function foo($x) { $x = 42; } 改了 $x,外面的变量纹丝不动。想改外面,必须声明为引用参数:function foo(&$x)。
常见错误现象:
— 在函数签名里漏写 &,却在调用时写 foo(&$var) —— PHP 8.0+ 已禁止这种“调用时加 &”的写法,直接报错
— 把数组传进函数后用 array_push,以为能自动扩容原数组,结果发现没变(因为没声明引用)
- 性能提示:传大数组进函数却不加
&,PHP 会在进入函数时触发 COW,若函数里只读不写,其实没额外开销 - 安全建议:除非明确需要修改原变量,否则别轻易用引用参数,会增加调用方的理解成本和耦合度
- 特别注意:
foreach的键值变量默认可写,但不会反向影响原数组——除非你显式用了&$value
真正容易被忽略的是 COW 的边界:它只对“未被引用”的变量生效。一旦出现任何一个 &,整条引用链上的变量就脱离 COW 保护,内存占用会立即翻倍。测性能别光看 memory_get_usage(),记得用 xdebug_debug_zval() 看 refcount 和 is_ref 字段。











