在 PHP 中确定两个对象是否相同的最快方法是什么?

问题描述 投票:0回答:4

假设我有一个对象(在本例中为 User 对象),并且我希望能够使用单独的类来跟踪更改。用户对象不必以任何方式改变它的行为才能发生这种情况。

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

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

选项1 也许我可以序列化每个版本,然后直接比较,或者散列它们并比较?

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

选项3 也许有一个简单的本机函数,如

objects_are_equal($object1,$object2);

最快的方法是什么?

php object comparison
4个回答
18
投票

在不修改对象的情况下访问对象的所有(公共、受保护和私有)属性的唯一方法是通过反射。如果您愿意,您可以在修改之前克隆对象,然后使用反射函数循环遍历两个对象之一的不同属性并比较值来比较它们。这将有效地告诉您哪些属性发生了变化。

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

也就是说,在更改内容时跟踪更改的内容不是更容易吗?


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()


2
投票

php.net 上有一整个页面只处理比较对象:

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

也值得一读:

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

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

还有一种快速方法是在类中声明一个静态方法,该方法仅比较相关的“属性”,例如“用户名”,“密码”,“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
    }
    
    
    };       

1
投票

通过反射比较 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;
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.