对象的比较

在 PHP 4 中,对象比较的规则十分简单:如果两个对象是同一个类的实例,且它们有相同的属性和值,则这两个对象相等。类似的规则还适用与用全等符(===)对两个对象的比较。

如果执行以下范例中的代码:

例子 18-1. PHP 4 中对象比较范例

<?php
function bool2str($bool) {
    if (
$bool === false) {
            return
'FALSE';
    } else {
            return
'TRUE';
    }
}

function
compareObjects(&$o1, &$o2) {
    echo
'o1 == o2 : '.bool2str($o1 == $o2)."\n";
    echo
'o1 != o2 : '.bool2str($o1 != $o2)."\n";
    echo
'o1 === o2 : '.bool2str($o1 === $o2)."\n";
    echo
'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
}

class
Flag {
    var
$flag;

    function
Flag($flag=true) {
            
$this->flag = $flag;
    }
}

class
SwitchableFlag extends Flag {

    function
turnOn() {
        
$this->flag = true;
    }

    function
turnOff() {
        
$this->flag = false;
    }
}

$o = new Flag();
$p = new Flag(false);
$q = new Flag();

$r = new SwitchableFlag();

echo
"Compare instances created with the same parameters\n";
compareObjects($o, $q);

echo
"\nCompare instances created with different parameters\n";
compareObjects($o, $p);

echo
"\nCompare an instance of a parent class with one from a subclass\n";
compareObjects($o, $r);
?>

上例将输出:

Compare instances created with the same parameters
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

Compare instances created with different parameters
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Compare an instance of a parent class with one from a subclass
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
这和按照比较规则推测的结果一致。当且仅当出自同一个类且属性及其值都相同的对象被认为是相等且完全相同的。

即使对于具有对象成分的类,比较的规则也相同。在以下的范例中建立了一个容器类来储存 Flag 对象的一个相关数组。

例子 18-2. PHP 4 中复合对象的比较

<?php
class FlagSet {
    var
$set;

    function
FlagSet($flagArr = array()) {
        
$this->set = $flagArr;
    }

    function
addFlag($name, $flag) {
        
$this->set[$name] = $flag;
    }

    function
removeFlag($name) {
        if (
array_key_exists($name, $this->set)) {
            unset(
$this->set[$name]);
        }
    }
}


$u = new FlagSet();
$u->addFlag('flag1', $o);
$u->addFlag('flag2', $p);
$v = new FlagSet(array('flag1'=>$q, 'flag2'=>$p));
$w = new FlagSet(array('flag1'=>$q));

echo
"\nComposite objects u(o,p) and v(q,p)\n";
compareObjects($u, $v);

echo
"\nu(o,p) and w(q)\n";
compareObjects($u, $w);
?>

上例将输出:

Composite objects u(o,p) and v(q,p)
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

u(o,p) and w(q)
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE


add a note add a note User Contributed Notes
magicturkey at gmail dot com
29-Mar-2006 11:15
If youre just checking to see if the variables both reference the same object, instead of having a variable set up beforehand you could do away with the GLOBALS and have something like..
e.g.

<?php
class Foo {
  var
$serial;
  function
Foo() {
  
// Rest of constructor...
 
}
 
// Rest of class definition...
}

$baz->serial = -1;
$bar->serial = time();
if(
$bar->serial == $baz->serial) {
  echo
"Same";
}
?>
pferlet at aston dot fr
29-Apr-2005 08:24
Using globals isn't really well... you can use pattern singleton to verify this.
jazfresh at hotmail dot com
09-Apr-2004 12:44
An addendum to the post below:

If you are comparing two objects and you know that they will be of the same type (you're just not sure if they refer to the same object or not), then there is an easier and faster way to do the comparison, and this also avoids the infinite recursion problem with circular references described in the post below.

In the constructor of your object, set a "serial" attribute from a global variable that is incremented whenever a new object is created. Then you just have to compare serial numbers to see if the objects are the same.

e.g.

<?php
$FooSerial
= 0;
class
Foo {
  var
$serial;
  function
Foo() {
  
$this->serial = $GLOBALS['FooSerial']++;
  
// Rest of constructor...
 
}
 
// Rest of class definition...
}

if(
$bar->serial == $baz->serial) {
  echo
"Same";
}
?>
jazfresh at hotmail dot com
08-Apr-2004 12:18
PHP4 compares two objects (say, $a and $b) by comparing the type and all the attributes. If an attribute is an object, PHP4 will recursively call "if($a.attribute === $b.attribute)" to determine equality. However, this is a problem if a circular reference has been formed. The recursion will go on forever, and you will get the error message:

"Fatal error: Nesting level too deep - recursive dependency?"

Example, where the comparison will never terminate because PHP4 will forever recurse with comparisons of the attribute.
<?php
class Test {
       var
$obj;
}
$foo =& new Test;
$bar =& new Test;
$foo->obj =& $bar; // Make circular reference
$bar->obj =& $foo;

if(
$foo === $bar) {
      
baz();
}
?>
First PHP4 does ($foo === $bar), which expands into ($foo.obj === $bar.obj), which expands into ($bar.obj === $foo.obj), and so on and so on.

To avoid this situation, you must compare objects manually by comparing the two object's attributes and avoiding comparisons on attributes where a circular reference could arise.

This issue is easily avoided in PHP5, where objects can be compared via references rather than the object contents.