PHP中文手册

版权信息

PHP 手册

入门指引

安装与配置

语言参考

安全

特点

函数参考

PHP 核心:骇客指南

FAQ

附录

构造函数中的引用

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

<?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”默认并不返回引用,而返回一个拷贝。

Note: 在返回拷贝而不是引用中并没有性能上的损失(因为 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  {
    function 
A ( $i ) {
        
$this -> value  $i ;
        
// 试着想明白为什么这里不需要引用
        
$this -> = new  B ( $this );
    }

    function 
createRef () {
        
$this -> = new  B ( $this );
    }

    function 
echoValue () {
        echo 
"<br />" , "class " , get_class ( $this ), ': ' , $this -> value ;
    }
}


class 
{
    function 
B (& $a ) {
        
$this -> = & $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