Каков самый быстрый способ сравнения двух объектов в PHP?

предположим, у меня есть объект - объект пользователя в этом случае - и я хотел бы иметь возможность отслеживать изменения с помощью отдельного класса. Пользовательский объект не должен каким-либо образом изменять свое поведение, чтобы это произошло.

поэтому мой отдельный класс создает "чистую" копию, сохраняет ее где-то локально, а затем позже может сравнить объект пользователя с исходной версией, чтобы увидеть, изменилось ли что-нибудь во время его жизни.

есть ли функция, шаблон или что-нибудь, что может быстро сравнить две версии объекта User?

1 Может быть, я мог бы сериализовать каждую версию и напрямую сравнить или хэшировать их и сравнивать?

2 Может быть, мне просто создать ReflectionClass, запустить каждое из свойств класса и посмотреть, имеют ли две версии одинаковые значения свойств?

3 Возможно, есть простая собственная функция, такая как objects_are_equal($object1,$object2);?

какой самый быстрый способ сделать это?

4 ответов


единственный способ получить доступ к всех (public, protected и Private) свойства объекта без изменения его через отражение. Вы могли бы, если бы захотели,клон объект, прежде чем он будет изменен, а затем сравнить их с помощью функций отражения для цикла через различные свойства одного из двух объектов и сравнения значений. Это бы эффективно сказало вам, какие свойства изменились.

Если все, что вы хотите увидеть, это или объекты не изменились, вы можете использовать операторы == или===. Взгляните на сравнение объектов раздел документации PHP.

это сказало, не было бы просто легче отслеживать, что вы изменили, как вы меняете их?


есть целый сайт на php.net только при сравнении объектов:

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

также хорошее чтение:

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

Я бы сказал, что вы должны использовать метод "clone" при копировании объекта, а затем сравнить, как сказано в 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
    }


    };       

вот фрагмент кода, который поддерживает частные свойства:

$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 {
        // ...
    }
}


Обратите внимание, что if $object_1 обладает свойствами, которые $object_2 не имеет, приведенный выше код будет создавать ошибки при попытке получить к ним доступ.

для такого случая вам нужно будет сначала пересечь $reflection_1->getProperties() С $reflection_2->getProperties().


простой пример сравнения класса 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;
    }

}