downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

Indução de Tipo> <Clonando objetos
Last updated: Fri, 13 Nov 2009

view this page in

Comparando objetos

No PHP 5, comparação de objetos é mais complicada que no PHP 4 e mais de acordo com o que é esperado de uma Linguagem Orientada a Objetos (não que PHP 5 seja uma delas).

Quando usar o operador de comparação (==), variáveis objeto são comparadas de maneira simples, nominalmente: Duas instâncias de objetos são iguais se tem os mesmos atributos e valores, e são instâncias da mesma classe.

Por outro lado, quando usando o operador de identidade (===), variáveis objetos são identicas se e somente se elas se referem a mesma instância da mesma classe.

Um exemplo evidenciará essas regras.

Exemplo #1 Exemplo de comparação de objetos no PHP 5

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

function 
compareObjetos(&$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 
OutraFlag
{
    var 
$flag;

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

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

echo 
"Duas instâncias da mesma classe\n";
compareObjetos($o$p);

echo 
"\nDuas referências para a mesma instância\n";
compareObjetos($o$q);

echo 
"\nInstâncias de duas classes diferentes\n";
compareObjetos($o$r);
?>

O exemplo acima irá imprimir:

Duas instâncias da mesma classe
o1 == o2 : VERDADEIRO
o1 != o2 : FALSO
o1 === o2 : FALSO
o1 !== o2 : VERDADEIRO

Duas referências para a mesma instância
o1 == o2 : VERDADEIRO
o1 != o2 : FALSO
o1 === o2 : VERDADEIRO
o1 !== o2 : FALSO

Instâncias de duas classes diferentes
o1 == o2 : FALSO
o1 != o2 : VERDADEIRO
o1 === o2 : FALSO
o1 !== o2 : VERDADEIRO

Nota: Extensões podem definir suas regras para comparação de objetos.



Indução de Tipo> <Clonando objetos
Last updated: Fri, 13 Nov 2009
 
add a note add a note User Contributed Notes
Comparando objetos
RPaseur at NationalPres dot org
08-Oct-2009 11:09
SimpleXML Objects are different, even if made from the same XML.

<?php // RAY_SimpleXML_compare.php
error_reporting(E_ALL);
echo
"<pre>\n";

// TWO SimpleXML OBJECTS ARE NOT EQUAL WITH COMPARISON OPERATORS.  PHP 5.2.10

// AN XML STRING
$xml = '<?xml version="1.0" encoding="utf-8"?>
<thing>
  <number>123456</number>
  <email>user@example.com</email>
  <state>CA</state>
</thing>'
;

// SHOW THE XML STRING
echo htmlentities($xml);

// MAKE TWO OBJECTS
$obj1 = SimpleXML_Load_String($xml);
$obj2 = SimpleXML_Load_String($xml);

// COMPARE OBJECTS AND FIND THAT THIS ECHOS NOTHING AT ALL
if ($obj1 === $obj2) echo "\n\nOBJECTS IDENTICAL ";
if (
$obj1 ==  $obj2) echo "\n\nOBJECTS EQUAL ";

// SHOW THE OBJECTS - NOTE DIFFERENT SimpleXMLElement NUMBERS
echo "\n\n";
var_dump($obj1);
var_dump($obj2);

// ITERATE OVER THE OBJECTS
foreach ($obj1 as $key => $val1)
{
   
$val2 = $obj2->$key;
   
var_dump($val1);
   
var_dump($val2);
    if (
$val1 == $val2) echo "\n\nOBJECTS EQUAL"; // ECHOS NOTHING

// RECAST AS STRINGS AND COMPARE AGAIN
   
$val1 = (string)$val1;
   
$val2 = (string)$val2;
    if (
$val1 === $val2) echo "STRINGS IDENTICAL: $key => $val1 \n\n"; // CONMPARISON SHOWS STRINGS IDENTICAL
}
?>
Hayley Watson
16-Sep-2008 10:33
This has already been mentioned (see jazfresh at hotmail.com's note), but here it is again in more detail because for objects the difference between == and === is significant.

Loose equality (==) over objects is recursive: if the properties of the two objects being compared are themselves objects, then those properties will also be compared using ==.

<?php
class Link
{
    public
$link; function __construct($link) { $this->link = $link; }
}
class
Leaf
{
    public
$leaf; function __construct($leaf) { $this->leaf = $leaf; }
}

$leaf1 = new Leaf(42);
$leaf2 = new Leaf(42);

$link1 = new Link($leaf1);
$link2 = new Link($leaf2);

echo
"Comparing Leaf object equivalence: is \$leaf1==\$leaf2? ", ($leaf1 == $leaf2  ? "Yes" : "No"), "\n";
echo
"Comparing Leaf object identity: is \$leaf1===\$leaf2? ",   ($leaf1 === $leaf2 ? "Yes" : "No"), "\n";
echo
"\n";
echo
"Comparing Link object equivalence: is \$link1==\$link2? ",($link1 == $link2  ? "Yes" : "No"), "\n";
echo
"Comparing Link object identity: is \$link1===\$link2? ",  ($link1 === $link2 ? "Yes" : "No"), "\n";
?>

Even though $link1 and $link2 contain different Leaf objects, they are still equivalent because the Leaf objects are themselves equivalent.

The practical upshot is that using "==" when "===" would be more appropriate can result in a severe performance penalty, especially if the objects are large and/or complex. In fact, if there are any circular relationships involved between the objects or (recursively) any of their properties, then a fatal error can result because of the implied infinite loop.

<?php
class Foo { public $foo; }
$t = new Foo; $t->foo = $t;
$g = new Foo; $g->foo = $g;

echo
"Strict identity:   ", ($t===$g ? "True" : "False"),"\n";
echo
"Loose equivalence: ", ($t==$g  ? "True" : "False"), "\n";
?>

So preference should be given to comparing objects with "===" rather than "=="; if two distinct objects are to be compared for equivalence, try to do so by examining suitable individual properties. (Maybe PHP could get a magic "__equals" method that gets used to evaluate "=="? :) )
wbcarts at juno dot com
08-Sep-2008 08:36
COMPARING OBJECTS using PHP's usort() method.

PHP and MySQL both provide ways to sort your data already, and it is a good idea to use that if possible. However, since this section is on comparing your own PHP objects (and that you may need to alter the sorting method in PHP), here is an example of how you can do that using PHP's "user-defined" sort method, usort() and your own class compare() methods.

<?php

/*
 * Employee.php
 *
 * This class defines a compare() method, which tells PHP the sorting rules
 * for this object - which is to sort by emp_id.
 *
 */
class Employee
{
    public
$first;
    public
$last;
    public
$emp_id;     // the property we're interested in...

   
public function __construct($emp_first, $emp_last, $emp_ID)
    {
       
$this->first = $emp_first;
       
$this->last = $emp_last;
       
$this->emp_id = $emp_ID;
    }

   
/*
     * define the rules for sorting this object - using emp_id.
     * Make sure this function returns a -1, 0, or 1.
     */
   
public static function compare($a, $b)
    {
        if (
$a->emp_id < $b->emp_id) return -1;
        else if(
$a->emp_id == $b->emp_id) return 0;
        else return
1;
    }

    public function
__toString()
    {
        return
"Employee[first=$this->first, last=$this->last, emp_id=$this->emp_id]";
    }
}

# create a PHP array and initialize it with Employee objects.
$employees = array(
  new
Employee("John", "Smith", 345),
  new
Employee("Jane", "Doe", 231),
  new
Employee("Mike", "Barnes", 522),
  new
Employee("Vicky", "Jones", 107),
  new
Employee("John", "Doe", 2),
  new
Employee("Kevin", "Patterson", 89)
);

# sort the $employees array using Employee compare() method.
usort($employees, array("Employee", "compare"));

# print the results
foreach($employees as $employee)
{
  echo
$employee . '<br>';
}
?>

Results are now sorted by emp_id:

Employee[first=John, last=Doe, emp_id=2]
Employee[first=Kevin, last=Patterson, emp_id=89]
Employee[first=Vicky, last=Jones, emp_id=107]
Employee[first=Jane, last=Doe, emp_id=231]
Employee[first=John, last=Smith, emp_id=345]
Employee[first=Mike, last=Barnes, emp_id=522]

Important Note: Your PHP code will never directly call the Employee's compare() method, but PHP's usort() calls it many many times. Also, when defining the rules for sorting, make sure to get to a "primitive type" level... that is, down to a number or string, and that the function returns a -1, 0, or 1, for reliable and consistent results.

Also see: http://www.php.net/manual/en/function.usort.php for more examples of PHP's sorting facilities.
wbcarts at juno dot com
06-Sep-2008 09:02
COMPARISONS AND EQUALITY are NOT the same

I'm not sure that the PHP Example #1 above is clear enough. In my own experience, I have found there is a distinct difference between a "comparison" and a "test for equality". The difference is found in the possible return values of the function being used, for example.

/*
 * Test two values for EQUALITY - returns (boolean) TRUE or FALSE.
 */
function equals($a, $b)
{
  return ($a == $b);
}

/*
 * COMPARE two values - returns (int) -1, 0, or 1.
 */
function compare($a, $b)
{
  if($a < $b) return -1;
  else if($a == $b) return 0;
  else if($a > $b) return 1;
  else return -1;
}

My examples clarify the difference between "making a comparison" and "testing for equality". You can substitute any of the "==" with "===" for example, but the point is on the possible return values of the function. All tests for EQUALITY will return TRUE or FALSE, and a COMPARISON will give a "<", "==", or ">" answers... which you can then use for sorting.
cross+php at distal dot com
05-Mar-2008 04:50
In response to "rune at zedeler dot dk"s comment about class contents being equal, I have a similar issue.  I want to sort an array of objects using sort().

I know I can do it with usort(), but I'm used to C++ where you can define operators that allow comparison.  I see in the zend source code that it calls a compare_objects function, but I don't see any way to implement that function for an object.  Would it have to be an extension to provide that interface?

If so, I'd like to suggest that you allow equivalence and/or comparison operations to be defined in a class definition in PHP.  Then, the sorts of things rune and I want to do would be much easier.
dionyziz at deviantart dot com
11-Mar-2007 03:20
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
?>
rune at zedeler dot dk
28-Feb-2007 04:34
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;
}
?>
rune at zedeler dot dk
28-Feb-2007 04:27
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;
}
?>
jazfresh at hotmail.com
08-Dec-2006 10:36
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

Indução de Tipo> <Clonando objetos
Last updated: Fri, 13 Nov 2009
 
 
show source | credits | stats | sitemap | contact | advertising | mirror sites