php变量赋值绝大多数是值拷贝,但对象、资源等类型默认按引用语义处理;$a = $b对普通变量是深拷贝,$obj1 = $obj2是对象标识符复制,强制值拷贝需clone,强制引用需&。

PHP变量赋值是值拷贝还是引用?
绝大多数情况下,PHP变量赋值是值拷贝(copy by value),但对象、资源和某些扩展类型默认按引用语义处理。这不是“有时引用有时值”,而是由类型决定的底层行为。
常见错误现象:foreach 中修改数组元素却没生效;函数内改了数组,外部没变;对象属性修改却跨作用域生效。
-
$a = $b对普通变量(int、string、array)是深拷贝副本,互不影响 -
$obj1 = $obj2实际是“对象标识符”复制,两个变量指向同一对象实例 - 想强制值拷贝对象,得用
clone $obj;想强制引用赋值,用$a =& $b - PHP 7+ 的
array赋值在写时才真正复制(Copy-on-Write),性能友好但观察不到中间状态
什么时候必须用 & 符号做引用赋值?
只有当你明确需要两个变量共享同一内存地址,并且后续任意一方修改都同步反映到另一方时,才该用 &。它不是优化手段,而是语义需求。
典型使用场景:函数内修改传入的数组结构、构建链式数据结构、避免大数组重复拷贝(但需谨慎)。
立即学习“PHP免费学习笔记(深入)”;
- 函数参数中用
&$arr表示“允许函数修改原始数组”,调用时不能传字面量如func(&[1,2])(会报Only variables can be passed by reference) -
$a =& $b后,unset($b)不影响$a,因为引用关系已建立,$a持有独立引用 - 对
foreach中的值加&可直接修改原数组:foreach ($arr as &$v) { $v *= 2; },但循环结束后记得unset($v),否则$v仍引用最后一个元素,下次赋值可能出错
数组赋值的坑:特别是多维数组和 unset 后的行为
数组看似简单,但嵌套层级一深,赋值和销毁就容易误判“谁变了谁没变”。根本原因在于 PHP 数组是 HashTable 实现,不是纯值类型。
常见错误现象:unset($arr['key']) 后,$new = $arr 还包含被删的键;二维数组 $a['x']['y'] = 1 后,$b = $a 修改 $b['x']['y'] 却不影响 $a(因为子数组仍是值拷贝)。
- 单层数组赋值
$b = $a是完整副本,unset($a['k'])不影响$b - 但若
$a['nested'] = &$someVar,那$b = $a后,$b['nested']依然引用$someVar—— 引用关系随变量一起复制 - 用
array_merge()或+合并数组时,键冲突处理不同:$a + $b保留左数组键,array_merge($a, $b)用右数组覆盖左数组同名数字键,字符串键则后者覆盖前者
PHP 8.1+ 属性提升与只读类对赋值的影响
启用 readonly 类或属性后,“赋值”变成一次性操作,后续任何写入都会抛出 Fatal error: Cannot modify readonly property。这不是语法糖,是运行时强约束。
这改变了你对“变量可变性”的直觉,尤其在封装配置、DTO 或实体类时。
-
class Config { public readonly string $host; }→ 构造函数里赋一次,之后$cfg->host = 'x'直接崩溃 -
readonly数组或对象属性,其内部元素/属性仍可变(除非它们自己也是 readonly),比如public readonly array $data;允许$obj->data[] = 1 - 想彻底冻结整个结构,得组合用
readonly+array_is_list()+ 自定义不可变逻辑,PHP 不提供deep readonly
readonly 就万事大吉,结果子元素还在悄悄变。











