2016-01-13 37 views
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_methodes但这会返回所有的方法,而不仅仅是getters和setter。当然,过滤get...set...的方法名称当然会起作用,但这更像是一种黑客而不是“干净利落”的解决方案。

总之:有没有任何“正确”的方式来自动检查两个PHP对象是否相等?

回答

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) 

这可能是也可能不是够你用的。


作为pointed out by 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

这会在循环引用上失败(导致致命错误)。使用它时记住这一点很重要。 –

+0

确实。将这个添加到答案中(还有其他问题,但这可能是最明显和戏剧性的)。 – VolkerK

+0

那么,“循环引用” - 我的意思不仅是狭义的对象情况。可能不存在交叉对象引用,而是交叉属性(或内联属性)递归。没有嵌套对象的示例是数组,如[此片段](https://3v4l.org/MZm12)。所以你的示例是有效的,我只是注意到,遍历比较的递归结构在PHP中运行不正常。减轻这种情况的常见方法是使用DFS和实际上自定义的用户功能(通过反射对象) –

0

您可以使用反射来做到这一点,但我不认为这是一个好主意。也许序列化()是一个更好的解决方案?

function isEquals(self $obj){ 
return serialize($obj)===serialize($this) 
}