自动检查两个对象是否相等?

4

我需要检查两个PHP对象是否相等,包括相等的值。当然,我可以轻松地在类中添加一个isEqualTo(...)方法来比较所有相关的值。然而,具体的类将在不久的将来发生变化,我想知道是否有任何自动化的方式来做到这一点。

示例:

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;
    }
} 

这显然会起作用。当然,我知道比较someObject的限制(需要完全相同的对象才能为真),但这没关系。
然而,类Contact将在不久的将来进行扩展。每次我向类中添加新属性/值时,都必须将它们添加到isEqualTo中。这没什么大不了的,但有点繁琐。
那么,有没有办法实现isEqualTo以自动检查所有可用的公共属性?
我找到了get_class_varsget_object_vars,但这些方法只适用于可以直接访问的变量,而不能使用getter和setter。
我发现get_class_methods,但这返回所有方法,而不仅仅是getter和setter。当然,通过get...set...过滤方法名称会起作用,但这更像是一种hack而不是“漂亮而干净”的解决方案。
简而言之:有没有任何“正确”的方法自动检查两个PHP对象是否相等?
2个回答

4

我不会说这是“正确”的方式,但是如果您不想实现/维护自己的比较函数/方法,您可能会对php的默认行为感兴趣,包括保护/私有属性的比较:

<?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
);

打印

bool(false)
bool(true)

这可能对您足够或者不够。


正如 Alma Do 指出的那样, 循环引用比如...

<?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
);

会导致一个 Fatal error: Nesting level too deep - recursive dependency? 错误。


1
这将在循环引用时失败(以一种糟糕的方式,导致致命错误)。在使用它时记住这一点非常重要。 - Alma Do
确实。将此添加到答案中(还有其他问题,但这可能是最明显和最显着的)。 - VolkerK
“循环引用”不仅指狭窄的对象情况。可能没有跨对象引用,而是交叉属性(或内联属性)递归。没有嵌套对象的示例案例是数组,例如此片段中的数组。因此,您的示例是有效的,我只是注意到在PHP中遍历递归结构时并不好用。缓解这种情况的常见方法是使用DFS和自定义用户函数(通过Reflection for objects)。 - Alma Do

0
你可以使用反射来实现这个功能,但我认为这不是一个好主意。也许使用serialize()会是更好的解决方案?
function isEquals(self $obj){
return serialize($obj)===serialize($this)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接