在PHP中比较两个对象的最快方法是什么?

时间:2012-03-26 05:14:27

标签: php object

假设我有一个对象 - 在这种情况下是一个User对象 - 我希望能够跟踪一个单独的类的更改。用户对象不应该以任何方式改变它的行为。

因此,我的单独类创建它的“干净”副本,将其存储在本地某个位置,然后稍后可以将User对象与原始版本进行比较,以查看在其生命周期内是否有任何更改。

是否有可以快速比较User对象的两个版本的函数,模式或任何东西?

选项1 也许我可以序列化每个版本,直接比较,或哈希并比较?

选项2 也许我应该简单地创建一个ReflectionClass,运行该类的每个属性,看看这两个版本是否具有相同的属性值?

选项3 也许有一个简单的原生函数,如objects_are_equal($object1,$object2);

最快的方法是什么?

4 个答案:

答案 0 :(得分:13)

访问对象的所有(公共,受保护和私有)属性而不修改它的唯一方法是reflection。如果您想要,可以在修改之前对clone对象进行比较,然后使用反射函数对它们进行比较,以循环浏览两个对象之一的不同属性并比较值。这将有效地告诉你哪些属性已经改变。

如果您只想知道对象是否已更改,则可以使用==或===运算符。查看PHP文档的comparing objects部分。

那就是说,当你改变它们时,跟踪你改变了什么并不容易?

答案 1 :(得分:2)

php.net上有一个完整的网站只处理比较对象:

http://php.net/manual/en/language.oop5.object-comparison.php

也很好读:

http://www.tuxradar.com/practicalphp/6/12/0

我想说你应该在复制你的对象时使用“clone”方法,然后再按照php.net文章的说法进行比较。

同样快速的方法是在类中声明一个静态方法,只比较相关的“属性”,比如说“username”,“password”,“cookie”,......

    class User
    {

    public $username;
    public $password;
    public $cookie;

    # other code

    public static function compare(&$obj1, &$obj2)
    {
    if ($obj1->username != $obj2->username)
        return 0
    if ($obj1->password != $obj2->password)
        return 0
    if ($obj1->cookie != $obj2->cookie)
        return 0
    return 1
    }


    };       

答案 2 :(得分:2)

以下是一段支持私有属性的代码:

$reflection_1 = new \ReflectionClass($object_1);
$reflection_2 = new \ReflectionClass($object_2);

$props_1 = $reflection_1->getProperties();

foreach ($props_1 as $prop_1) {

    $prop_1->setAccessible(true);
    $value_1 = $prop_1->getValue($object_1);

    $prop_2 = $reflection_2->getProperty($prop_1->getName());

    $prop_2->setAccessible(true);
    $value_2 = $prop_2->getValue($object_2);

    if ($value_1 === $value_2) {
        // ...
    } else {
        // ...
    }
}


请注意,如果$object_1具有$object_2没有的属性,则上述代码在尝试访问时会产生错误。

对于这种情况,您首先需要与$reflection_1->getProperties()相交 $reflection_2->getProperties()

答案 3 :(得分:0)

通过反射比较dto类的简单示例

class InvoiceDetails
{
    /** @var string */
    public $type;

    /** @var string */
    public $contractor;

    /** @var string */
    public $invoiceNumber;

    /** @var \DateTimeInterface|null */
    public $saleDate;

    /** @var \DateTimeInterface|null */
    public $issueDate;

    /** @var \DateTimeInterface|null */
    public $dueDate;

    /** @var string */
    public $payment;

    /** @var string */
    public $status;


    public function isEqual(InvoiceDetails $details): bool
    {
        $reflection = new \ReflectionClass(self::class);

        /** @var \ReflectionProperty $property */
        foreach ($reflection->getProperties() as $property) {
            $name = $property->getName();
            if ($this->$name !== $details->$name) {
                return false;
            }
        }

        return true;
    }

}