假设我有一个对象 - 在这种情况下是一个User对象 - 我希望能够跟踪一个单独的类的更改。用户对象不应该以任何方式改变它的行为。
因此,我的单独类创建它的“干净”副本,将其存储在本地某个位置,然后稍后可以将User对象与原始版本进行比较,以查看在其生命周期内是否有任何更改。
是否有可以快速比较User对象的两个版本的函数,模式或任何东西?
选项1 也许我可以序列化每个版本,直接比较,或哈希并比较?
选项2 也许我应该简单地创建一个ReflectionClass,运行该类的每个属性,看看这两个版本是否具有相同的属性值?
选项3
也许有一个简单的原生函数,如objects_are_equal($object1,$object2);
?
最快的方法是什么?
答案 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;
}
}