PHP Manual
后退 | 章 18. 类与对象(PHP 4) | 前进

# 构造函数中的引用

在构造函数中创建引用可能会导致混淆的结果。本节以教程形式帮助避免问题。

`<?php class Foo { function Foo($name) { // 在全局数组 $globalref 中建立一个引用 global $globalref; $globalref[] = &$this; // 将名字设定为传递的值 $this->setName($name); // 并输出之 $this->echoName(); } function echoName() { echo "<br>",$this->name; } function setName($name) { $this->name = $name; } } ?>`

下面来检查一下用拷贝运算符 = 创建的 $bar1 和用引用运算符 =& 创建的 $bar2 有没有区别...

`<?php $bar1 = new Foo('set in constructor'); $bar1->echoName(); $globalref[0]->echoName(); /* 输出： set in constructor set in constructor set in constructor */ $bar2 =& new Foo('set in constructor'); $bar2->echoName(); $globalref[1]->echoName(); /* 输出： set in constructor set in constructor set in constructor */ ?>`

显然没有区别，但实际上有一个非常重要的区别：$bar1 和 $globalref[0] 并没有被引用，它们不是同一个变量。这是因为“new”默认并不返回引用，而返回一个拷贝。

> 注: 在返回拷贝而不是引用中并没有性能上的损失（因为 PHP 4 及以上版本使用了引用计数）。相反更多情况下工作于拷贝而不是引用上更好，因为建立引用需要一些时间而建立拷贝实际上不花时间（除非它们都不是大的数组或对象，而其中之一跟着另一个变，那使用引用来同时修改它们会更聪明一些）。

要证明以上写的，看看下面的代码。

`<?php // 现在改个名字，你预期什么结果？ // 你可能预期 $bar1 和 $globalref[0] 二者的名字都改了... $bar1->setName('set from outside'); // 但如同前面说的，并不是这样。 $bar1->echoName(); $globalref[0]->echoName(); /* 输出为： set from outside set in constructor */ // 现在看看 $bar2 和 $globalref[1] 有没有区别 $bar2->setName('set from outside'); // 幸运的是它们不但相同，根本就是同一个变量。 // 因此 $bar2->name 和 $globalref[1]->name 也是同一个变量。 $bar2->echoName(); $globalref[1]->echoName(); /* 输出为： set from outside set from outside */ ?>`

最后给出另一个例子，试着理解它。

`<?php class A { function A($i) { $this->value = $i; // 试着想明白为什么这里不需要引用 $this->b = new B($this); } function createRef() { $this->c = new B($this); } function echoValue() { echo "<br>","class ",get_class($this),': ',$this->value; } } class B { function B(&$a) { $this->a = &$a; } function echoValue() { echo "<br>","class ",get_class($this),': ',$this->a->value; } } // 试着理解为什么这里一个简单的拷贝会在下面用 * // 标出来的行中产生预期之外的结果 $a =& new A(10); $a->createRef(); $a->echoValue(); $a->b->echoValue(); $a->c->echoValue(); $a->value = 11; $a->echoValue(); $a->b->echoValue(); // * $a->c->echoValue(); /* 输出为： class A: 10 class B: 10 class B: 10 class A: 11 class B: 11 class B: 11 */ ?>`

后退 | 起点 | 前进
魔术函数 __sleep 和 __wakeup | 上一级 | PHP 4 中对象的比较