International PHP Conference 2015

객체 비교

비교 연산 (==) 을 사용할때, 객체 변수는 간단한 방식으로 비교됩니다. 즉, 두 객체의 인스턴스가 동일한 속성과 값을 가지고, 같은 클래스의 인스턴스라면 동일하다고 합니다.

일치 연산 (===) 을 사용할때, 같은 클래스의 동일한 인스턴스를 참조하는 경우에만 동일하다고 합니다.

이 규칙들이 다음 예제에 명확히 설명되어 있습니다.

Example #1 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);
?>

위 예제의 출력:

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:

확장모듈은 객체 비교 연산 (==) 에 대한 고유의 규칙을 정의할 수 있습니다.

add a note add a note

User Contributed Notes 11 notes

up
28
jazfresh at hotmail.com
8 years ago
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
up
18
Anonymous
5 years ago
Comparison using <> operators should be documented.  Between two objects, at least in PHP5.3, the comparison operation stops and returns at the first unequal property found.

<?php

$o1
= new stdClass();
$o1->prop1 = 'c';
$o1->prop2 = 25;
$o1->prop3 = 201;
$o1->prop4 = 1000;

$o2 = new stdClass();
$o2->prop1 = 'c';
$o2->prop2 = 25;
$o2->prop3 = 200;
$o2->prop4 = 9999;

echo (int)(
$o1 < $o2); // 0
echo (int)($o1 > $o2); // 1

$o1->prop3 = 200;

echo (int)(
$o1 < $o2); // 1
echo (int)($o1 > $o2); // 0

?>
up
3
roberto dot ifpa dot ufra at gmail dot com
7 months ago
Este exemplo é bem simples.
No exemplo abaixo,  irei comparar dois Objetos, tanto para saber se eles são iguais e idênticos ou iguais, porém não idênticos ou são objetos diferentes.

<?php

class Visibilidades {

    private
$num;
   
//método construtor
   
function __construct($num) {
       
$this->num = $num;
    }
   
//comparando
   
function booleanNum (Visibilidades $obj) {
        if (
$this->num == $obj->num) {
            echo
"Iguais";
            if (
$this->num === $obj->num) {
                echo
" e Idênticos";
            } else {
                echo
",porém não Idênticos";
            }
        } else {
            echo
"Diferentes";
        }
    }
}

$Obj1 = new Visibilidades('123');
$Obj2 = new Visibilidades('123');

$Obj1->booleanNum($Obj2);
?>

Neste forma o resultado será: (Iguais e Idênticos).
Se modificar  <?php $Obj2 = new Visibilidades(123); ?> sem as aspas simples o resultado será: (Iguais, porém não Idênticos).
up
2
rune at zedeler dot dk
8 years ago
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;
}
?>
up
2
wbcarts at juno dot com
6 years ago
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.
up
0
cross+php at distal dot com
7 years ago
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.
up
0
rune at zedeler dot dk
8 years ago
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;
}
?>
up
-1
Hayley Watson
6 years ago
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 "=="? :) )
up
-1
nhuhoai
1 year ago
For comparison about two objects in a class, you can use an interface like this and customize your functions for each class:

<?php
interface EQU {
    public static function
compare( EQU $me, EQU $you );
    public function
equals( EQU $you );
}
?>

If you gotcha a super class, you can make generic functions (not safe but work with not complex class):

<?php
abstract class SuperClass {
    public function
__construct( ) {
       
// do what you need
   
}
    public static function
compare( $obj1, $obj2 ) {
        return
serialize( $obj1 ) == serialize( $obj2 );
    }
    public function
equals( $obj ) {
        return static::
compare( $this, $obj );
    }
}
?>
up
-3
Oddant
2 years ago
This example is way too much confusing, if you new to php comparison motor, you should think (after reading this example) that '==' is actually comparing the type of the objects. that's not true, it actually compares the type of the objects AND the properties of them.

<?php

class A {
    private
$value;
    function
__construct ($value)
    {
       
$this->value = $value;
    }
}
class
B {
    private
$value;
    function
__construct ($value)
    {
       
$this->value = $value;
    }
}

$a1 = new A (1);
$a2 = new A (2);
$b1 = new B (1);

var_dump( $a1 == $a2 );
var_dump( $a1 == $b1 );
?>
up
-3
dionyziz at deviantart dot com
8 years ago
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
?>
To Top