Какой самый быстрый способ сравнить два объекта в PHP? - PullRequest
11 голосов
/ 26 марта 2012

Допустим, у меня есть объект - в данном случае объект User - и я хотел бы иметь возможность отслеживать изменения в отдельном классе. Объект User не должен каким-либо образом изменять свое поведение, чтобы это произошло.

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

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

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

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

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

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

Ответы [ 4 ]

13 голосов
/ 26 марта 2012

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

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

Тем не менее, будет не проще отследить, что вы изменили по мере их изменения?

2 голосов
/ 15 ноября 2013

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

$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 голосов
/ 26 марта 2012

На 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
    }


    };       
0 голосов
/ 29 июня 2018

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

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...