php函数参数默认按值传递,对象因存储标识符而表现类似引用;需修改外部变量时才用&声明引用参数,且调用时应显式加&以提升可读性与安全性。

PHP 函数参数是传值还是传引用?
PHP 默认所有参数都是按值传递,但对象例外——对象变量本身是“引用的句柄”,所以修改对象属性会反映到原对象上,而重新赋值 $obj = new StdClass() 不会影响外部变量。
- 标量(
int、string、bool)、数组、资源默认复制一份,函数内改不影响调用方 - 对象(
stdClass、自定义类实例)传的是对象标识符(handle),不是内存地址,也不是完全的引用语义 - 如果真要让标量或数组被函数修改后影响外部,必须显式用
&声明引用参数:function foo(&$arr) { $arr[] = 1; } -
foreach遍历时加&也能改原数组,但容易漏掉unset($v)导致后续循环出错
什么时候必须加 & 符号?
只有当你需要函数内部直接修改调用方的变量值,并让这个修改在函数返回后依然生效时,才需要 &。这不是性能优化手段,也不是“更高级”的写法。
- 常见场景:批量处理并更新多个配置项,比如
parse_ini_file的替代实现中解析后直接填充传入的&$config - 错误用法:以为加
&能提升大数组性能——PHP 的写时复制(Copy-on-Write)机制下,不修改时根本不会复制,加引用反而可能阻止优化 - 函数签名一旦用了
&,调用时不能传表达式(如foo(&get_array())报错),只能传变量:$x = []; foo($x); - PHP 8.1+ 对引用参数有更严格检查,传
null或未定义变量会触发E_WARNING
对象传参为什么看起来像引用?
因为 PHP 中对象变量存储的是指向对象容器的标识符,类似指针但不可运算。你传的是这个标识符的副本,两个变量指向同一块对象数据区。
- ✅
$a->prop = 'new'会影响$b(如果$b = $a) - ❌
$a = new StdClass()不会影响$b,这只是把新标识符赋给$a - ⚠️
clone $a才真正断开关联;unset($a)只销毁变量,对象本身还在,直到所有引用消失 - 注意
json_encode($obj)这类函数会触发完整深拷贝逻辑,跟传参机制无关
函数定义里写 & 但调用时不加 &,会怎样?
语法上完全合法,PHP 会自动将实参转为引用。但这是隐式行为,可读性差,且容易掩盖 bug。
立即学习“PHP免费学习笔记(深入)”;
- 调用方完全看不出这个参数会被修改,比如
filter_input_array(INPUT_GET, $rules, $output)如果第三个参数是&$output,调用者可能根本没意识到$output已被重写 - 如果传的是字面量(
foo(42))或表达式(foo($x + 1)),PHP 7.4+ 会报Cannot pass parameter by reference - IDE 和静态分析工具(如 PHPStan)通常会警告这种“不透明”的引用传递,建议显式在调用处也加
&(虽然语法不要求)
最常被忽略的是:引用参数和对象行为混在一起时,调试难度陡增。比如一个函数同时接受 &$data 和 $obj,你以为只改了 $data,结果 $obj 的某个属性也被动变了——那大概率是 $obj 内部引用了 $data,而不是传参机制的问题。











