Search code examples
phpclassobjectequality

Auto-check equality of two objects?


I need to check if two PHP object are equal in terms of equal values. Of course I could easily add an isEqualTo(...) method to the class that compares all relevant values. However the concrete class will change in the near future and I would like to know if there is any automated way to do this.

Example:

class Contact {
    private name;       // String
    private phone;      // Int
    private someObject; // Custom Object

    public function getName() {
        return $this->name;
    }

    public function setName($newName) {
        $this->name = $newName;
    }


    public function getPhone() {
        return $this->phone;
    }

    public function setPhone($newPhone) {
        $this->phone = $newPhone;
    }


    public function getSomeObject() {
        return $this->someObject;
    }

    public function setSomeObject($newObj) {
        $this->someObject = $newObj;
    }


    // Manual Solution 
    public function isEqualTo($contact) {
         result  = $this->name == $contact->getName();
         result &= $this->phone == $contact->getPhone();

         result &= $this->someObject == $contact->getSomeObject();

         return result;
    }
} 

This would obviously work. Of course I am aware of the the limitation of comparing someObject (need to be the exact some object to be true) but this is OK.

However the class Contact will be extended in the near future. Everytime I add new properties/values to the class I have to add them to isEqualTo as well. No big deal but a little bit cumbersome.

So, is there any way to implement isEqualTo to automatically all available public properties?

I found get_class_vars and get_object_vars but these methodes will not work with getters and setters but only with vars that can be accessed directly.

I found get_class_methodes but this return all methodes and not only getters and setters. Filtering the methodes names by get... and set... would work of course, but this would be more like a hack than a "nice and clean" soltution.

In short: Is there any "correct" way to automatically check two PHP object for equality?


Solution

  • I wouldn't go so far as to say that this is the "correct" way, but since you don't want to implement/maintain your own comparison function/method you might be interested in php's default behaviour including the comparison of protected/private properties:

    <?php
    class Foo {
        private $x,$y,$z;
        public function __construct($x,$y,$z) {
            $this->x = $x;
            $this->y = $y;
            $this->z = $z;
        }
    }
    
    $f1 = new Foo(1,2,3);
    $f2 = new Foo(4,5,6);
    $f3 = new Foo(1,2,3);
    
    var_dump(
        $f1==$f2,
        $f1==$f3
    );
    

    prints

    bool(false)
    bool(true)
    

    which might or might not be sufficient for you.


    As pointed out by Alma Do, circular references like e.g.

    <?php
    class Foo {
        private $x,$y,$z;
        public function __construct($x,$y,$z) {
            $this->x = $x;
            $this->y = $y;
            $this->z = $z;
        }
    
        public function setZ($z) {
            $this->z = $z;
        }
    }
    
    
    $f1 = new Foo(1,2,3);
    $f2 = new Foo(4,5,6);
    $f3 = new Foo(1,2,3);
    
    $f1->setZ($f3);
    $f3->setZ($f1);
    
    
    var_dump(
        $f1==$f2,
        $f1==$f3
    );
    

    will cause a Fatal error: Nesting level too deep - recursive dependency?.