最近开始比较系统地学习 PHP (以阅读 PHP 官方手册为主),因此将会不定期地写一些学习笔记。水平有限,如有错误请指正。

说到 PHP 的对象,总有一句话:“ PHP 当中对象是按引用传递的,即每个包含对象的变量都持有对象的引用(reference),而不是整个对象的拷贝”。然而这里的“引用”并不是 C++ 程序员所习惯的“引用”——严格来说, PHP 的“对象的引用”其实是对象的标识符的一个拷贝

C++ 程序员所理解的引用只是对象的另一个名字,本身不占据任何存储空间(指针还储存着指向该对象的地址)。故而 C++ 的引用必须在声明时初始化,且不能再被修改。

而 PHP 的对象的引用则更接近指针,它储存着该对象的一个“标识符”(类似地址),传递对象时是在拷贝这个标识符。故而你可以修改一个引用使其指向另一个对象(其实是修改了这个引用所储存的标识符)。

如果我们使用 PHP 的引用操作符 & 来显式地引用一个“对象”(如前文所述,实际上引用的是对象的标识符),那么我们将会得到一个“对象的引用”的引用,修改原引用,那么这个“引用的引用”也会随之更改。

给一段代码,很能说明问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
class foo {
  public $bar = 1;
}

$a = new foo;   //$a其实也是一个引用
$b = $a;        //拷贝引用 ($a)=($b)={id1}

$a->bar = 2;
echo "b->bar = $b->bar\n";

$b->bar = 3;
echo "a->bar = $a->bar\n";
//修改了b,但实际上是修改了a和b所引用的同一个对象
//并不会引发 Copy On Write 创建一个新对象b

$a = new foo;   //$a被修改为一个新的引用,$b没有改变
                //($a)={id2} ($b)={id1}
$a->bar = 4;
echo "b->bar = $b->bar\n";

$b = &$a;       //显式地使用引用,b成为“对象的引用”的引用
$a = new foo;   //($a)={id3} ($b)=&($a)=&{id3}
$a->bar = 5;
echo "b->bar = $b->bar\n"
?>

代码输出:

1
2
3
4
b->bar = 2
a->bar = 3
b->bar = 3
b->bar = 5