Skip to content

中的引用与深浅拷贝

PHP 中的变量赋值默认是值拷贝,理解引用和拷贝机制对避免 Bug 很重要。

基础赋值(值拷贝)

php
$a = 5;
$b = $a;  // 值拷贝,$b 是 $a 的副本
$b = 10;
echo $a;  // 5,$a 不受影响
echo $b;  // 10

引用赋值

使用 & 符号创建引用,两个变量指向同一个内存地址:

php
$a = 5;
$b = &$a;  // 引用赋值
$b = 10;
echo $a;   // 10,$a 也被修改了

// 取消引用
unset($b);  // $a 仍然是 10

数组中的引用陷阱

php
// 问题:foreach 中使用引用
$arr = [1, 2, 3];
foreach ($arr as &$value) {
    $value *= 2;  // 意图:每个元素乘以2
}
// 结果:[2, 4, 6]

// 危险:引用未被销毁
foreach ($arr as $value) {
    // 这里会出问题,因为 $value 仍然是引用
}
// 结果可能是 [2, 4, 4] 而非预期

// 正确做法:unset 引用
unset($value);

深拷贝 vs 浅拷贝

php
// 浅拷贝:对象赋值默认是引用
$obj1 = new stdClass();
$obj1->name = '张三';
$obj2 = $obj1;  // 引用
$obj2->name = '李四';
echo $obj1->name;  // 李四

// 深拷贝:使用 clone
$obj3 = clone $obj1;
$obj3->name = '王五';
echo $obj1->name;  // 李四,$obj1 不受影响

// 深拷贝对象(含嵌套对象)
class Person {
    public $name;
    public $address;  // 另一个对象
    
    public function __clone() {
        // 克隆时深拷贝嵌套对象
        $this->address = clone $this->address;
    }
}

函数参数中的引用

php
// 传递引用,可以修改原变量
function swap(&$a, &$b) {
    $temp = $a;
    $a = $b;
    $b = $temp;
}

$x = 1;
$y = 2;
swap($x, $y);
echo "$x, $y";  // 2, 1

// 返回引用
function &getValue() {
    static $value = 0;
    return $value;
}

$val = &getValue();
$val = 5;  // 修改静态变量

注意事项

  1. 引用不是指针,不能对引用做指针运算
  2. 过度使用引用会降低代码可读性
  3. 对象默认是引用传递,不需要加 &
  4. 函数参数中使用引用时要小心,可能产生副作用

Binstork