
PHP 函数里传对象,到底是传值还是传引用?
PHP 7+ 中,对象参数默认是“按引用传递的副本”——不是纯引用,也不是纯值,而是对象标识符(handle)被复制。这意味着函数内对 $obj->prop 的修改会反映到原对象,但把 $obj 重新赋值为新对象,不会影响外部变量。
- 常见错误现象:
function foo($o) { $o = new stdClass(); }调用后原变量没变,误以为“没传引用” - 正确理解:对象变量存的是句柄,赋值操作复制的是句柄,不是对象本身,也不是 C 风格的指针
- 性能影响:传对象几乎不拷贝内存,比传大数组或序列化字符串高效得多
- 兼容性注意:PHP 5 中行为类似,但内部实现不同(Object Store),实际表现一致;PHP 8 无变化
想真正切断对象关联?得用 clone 或 unset
如果函数内需要完全隔离原对象(比如做临时修改又不想污染输入),不能靠参数类型声明或 & 符号“强制引用/非引用”,而要主动克隆。
-
clone创建浅拷贝:属性值照搬,嵌套对象仍共享句柄
示例:$copy = clone $obj; - 深拷贝需手动处理或实现
__clone()方法,否则嵌套对象仍联动 - 直接
unset($obj)或$obj = null只影响当前作用域变量,不影响外部 - 别用
&$obj声明来“防止修改”——这反而会让外部受函数内重赋值影响,适得其反
类型声明和 & 符号到底改了什么?
function bar(MyClass $obj) 或 function bar(&$obj) 改变的不是传递机制,而是约束条件和可赋值范围。
-
MyClass $obj:只校验类型,不改变传递行为;传入子类实例也合法 -
&$obj:要求调用时必须传变量(不能传new MyClass()或函数返回值),且函数内对$obj的重赋值(如$obj = new MyClass())会同步到外部变量 - 两者混用:
function bar(&MyClass $obj)合法但危险——既强制引用又强制类型,容易在调用处报Cannot pass parameter 1 by reference - 错误信息示例:
PHP Warning: Parameter 1 to bar() expected to be a reference,说明你用了 & 却传了临时值
什么时候该担心对象参数的副作用?
真正要警惕的不是“传参方式”,而是函数是否隐式修改了对象状态——尤其在不可变设计、单元测试或并发场景下。
立即学习“PHP免费学习笔记(深入)”;
- 典型踩坑点:函数接收
DateTime对象,调用$dt->modify('+1 day'),外部时间变了却没意识到 - API 设计建议:若函数语义是“计算”,应避免修改入参对象;必要时文档注明“会修改原对象”
- 测试时容易漏掉:mock 对象被意外修改,导致后续断言失败,但错误堆栈不指向该函数
- 静态分析工具(如 PHPStan)不会警告对象属性修改,这类逻辑耦合只能靠人盯或写防护性克隆
对象参数本身很轻量,麻烦永远出在“谁在什么时候改了哪个属性”——而不是句柄怎么传。








