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