2016-01-13 36 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) 
}