Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Language Reference : Classes and Objects (PHP 5) : Comparing objects

Comparing objects

In PHP 5, object comparison is more complicated than in PHP 4 and more in accordance to what one will expect from an Object Oriented Language (not that PHP 5 is such a language).

When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values, and are instances of the same class.

On the other hand, when using the identity operator (===), object variables are identical if and only if they refer to the same instance of the same class.

An example will clarify these rules.

Example 10.32. Example of object comparison in PHP 5

<?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
{
   public
$flag;

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

class
OtherFlag
{
   public
$flag;

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

$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();

echo
"Two instances of the same class\n";
compareObjects($o, $p);

echo
"\nTwo references to the same instance\n";
compareObjects($o, $q);

echo
"\nInstances of two different classes\n";
compareObjects($o, $r);
?>

The above example will output:

Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Two references to the same instance
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

Instances of two different classes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE


Note:

Extensions can define own rules for their objects comparison.

Code Examples / Notes » language.oop5.object_comparison

rune

Whoops, apparently I hadn't checked the array-part of the below very well.
Forgot to test if the arrays had same length, and had some misaligned parenthesis.
This one should work better :+)
<?
function deepCompare($a,$b) {
 if(is_object($a) && is_object($b)) {
   if(get_class($a)!=get_class($b))
     return false;
   foreach($a as $key => $val) {
     if(!deepCompare($val,$b->$key))
       return false;
   }
   return true;
 }
 else if(is_array($a) && is_array($b)) {
   while(!is_null(key($a)) && !is_null(key($b))) {
     if (key($a)!==key($b) || !deepCompare(current($a),current($b)))
       return false;
     next($a); next($b);
   }
   return is_null(key($a)) && is_null(key($b));
 }
 else
   return $a===$b;
}
?>


jazfresh

Note that when comparing object attributes, the comparison is recursive (at least, it is with PHP 5.2). That is, if $a->x contains an object then that will be compared with $b->x in the same manner. Be aware that this can lead to recursion errors:
<?php
class Foo {
   public $x;
}
$a = new Foo();
$b = new Foo();
$a->x = $b;
$b->x = $a;
print_r($a == $b);
?>
Results in:
PHP Fatal error:  Nesting level too deep - recursive dependency? in test.php on line 11


dionyziz

Note that classes deriving from the same parent aren't considered equal when comparing even using ==; they should also be objects of the same child class.
<?php
   class Mom {
       private $mAttribute;
       
       public function Mom( $attribute ) {
           $this->mAttribute = $attribute;
       }
       public function Attribute() {
            return $this->mAttribute;
       }
   }
   
   final class Sister extends Mom {
       public function Sister( $attribute ) {
           $this->Mom( $attribute );
       }
   }
   
   final class Brother extends Mom {
       public function Brother( $attribute ) {
           $this->Mom( $attribute );
       }
   }
   
   $sister = new Sister( 5 );
   $brother = new Brother( 5 );
   
   assert( $sister == $brother ); // will FAIL!
?>
This assertion will fail, because sister and brother are not of the same child class!
If you want to compare based on the parent class object type only, you might have to define a function for comparisons like these, and use it instead of the == operator:
<?php
   function SiblingsEqual( $a, $b ) {
       if ( !( $a instanceof Mom ) ) {
           return false;
       }
       if ( !( $b instanceof Mom ) ) {
           return false;
       }
       if ( $a->Attribute() != $b->Attribute() ) {
           return false;
       }
       return true;
   }
   assert( SiblingsEqual( $sister, $brother ) ); // will succeed
?>


donny

In a reaction to Jony dos Santos Kostetzer.
It does matter if they have different values. You're using the method Flag within the class Flag. This method returns the given parameter or, if no parameter is set, true.
The comparison functions compares the 2 outcomes. In your example true and 10. In PHP this would be similar to :
<?php
if (true == 10)
{
return true ;
}
?>
Which would return true. So you could say that the values have the same outcome even though the input is visibly not the same.
Another example :
<?php
/* ... */
$o = new Flag(1);
$p = new Flag(10);
/* ... */
echo "Two instances of the same class\n";
compareObjects($o, $p);
?>
output:
Two instances of the same class
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
as can be expected.


rune

I haven't found a build-in function to check whether two obects are identical - that is, all their fields are identical.
In other words,
<?
class A {
 var $x;
 function __construct($x) { $this->x = $x; }
}
$identical1 = new A(42);
$identical2 = new A(42);
$different = new A('42');
?>
Comparing the objects with "==" will claim that all three of them are equal. Comparing with "===" will claim that all are un-equal.
I have found no build-in function to check that the two identicals are
identical, but not identical to the different.
The following function does that:
<?
function deepCompare($a,$b) {
 if(is_object($a) && is_object($b)) {
   if(get_class($a)!=get_class($b))
     return false;
   foreach($a as $key => $val) {
     if(!deepCompare($val,$b->$key))
return false;
   }
   return true;
 }
 else if(is_array($a) && is_array($b)) {
   while(!is_null(key($a) && !is_null(key($b)))) {
     if (key($a)!==key($b) || !deepCompare(current($a),current($b)))
return false;
     next($a); next($b);
   }
   return true;
 }
 else
   return $a===$b;
}
?>


07-mar-2007 10:17

<?
class _testCompare
{
public $num=4;
}
$o1=new _testCompare;
$o2=new _testCompare;
echo 'Both eq: ',($o1==$o2?'true':'false'),"\n<br />\n";
$o2->num=8;
echo 'No eq: ',($o1==$o2?'true':'false'),"\n<br />\n";
$o2->num=4;
echo 'Both eq: ',($o1==$o2?'true':'false'),"\n<br />\n";
$o2->num='4';
echo 'Both paraeq: ',($o1==$o2?'true':'false'),"\n<br />\n";
/* output:
Both eq: true
No eq: false
Both eq: true
Both paraeq: true
*/
?>


jony

"When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values, and are instances of the same class."
Actually, it doesn't matter if they have different values:
<?php
/* ... */
$o = new Flag();
$p = new Flag(10);
/* ... */
echo "Two instances of the same class\n";
compareObjects($o, $p);
?>
output:
Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Jony dos Santos Kostetzer


Change Language


Follow Navioo On Twitter
Introduction
The Basics
Autoloading Objects
Constructors and Destructors
Visibility
Scope Resolution Operator (::)
Static Keyword
Class Constants
Class Abstraction
Object Interfaces
Overloading
Object Iteration
Patterns
Magic Methods
Final Keyword
Object cloning
Comparing objects
Reflection
Type Hinting
Late Static Bindings
eXTReMe Tracker