在 PHP 中比较两个对象的最快方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9866920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the fastest way to compare two objects in PHP?
提问by johnnietheblack
Let's say I have an object - a User object in this case - and I'd like to be able to track changes to with a separate class. The User object should not have to change it's behavior in any way for this to happen.
假设我有一个对象 - 在本例中为 User 对象 - 我希望能够使用单独的类跟踪更改。User 对象不应该以任何方式改变它的行为来发生这种情况。
Therefore, my separate class creates a "clean" copy of it, stores it somewhere locally, and then later can compare the User object to the original version to see if anything changed during its lifespan.
因此,我的单独类创建了它的“干净”副本,将其存储在本地某处,然后可以将 User 对象与原始版本进行比较,以查看在其生命周期内是否有任何更改。
Is there a function, a pattern, or anything that can quickly compare the two versions of the User object?
是否有函数、模式或任何可以快速比较 User 对象的两个版本的东西?
Option 1Maybe I could serialize each version, and directly compare, or hash them and compare?
选项 1也许我可以序列化每个版本,然后直接比较,或者散列它们并比较?
Option 2Maybe I should simply create a ReflectionClass, run through each of the properties of the class and see if the two versions have the same property values?
选项 2也许我应该简单地创建一个 ReflectionClass,遍历该类的每个属性并查看两个版本是否具有相同的属性值?
Option 3Maybe there is a simple native function like objects_are_equal($object1,$object2);
?
选项 3也许有一个简单的本机功能,如objects_are_equal($object1,$object2);
?
What's the fastest way to do this?
这样做的最快方法是什么?
回答by Francois Deschenes
The only way to access the all (public, protected and private) properties of an object without modifying it is through reflection. You could, if you wanted to, clonethe object before it's modified and then compare them by using the reflection functions to loop through the different properties of one of the two objects and comparing values. That would effectively tell you what properties have changed.
访问对象的所有(公共、受保护和私有)属性而不修改它的唯一方法是通过反射。如果您愿意,您可以在修改对象之前克隆该对象,然后通过使用反射函数遍历两个对象之一的不同属性并比较值来比较它们。这将有效地告诉您哪些属性发生了变化。
If all you care to see is whether or not the objects have changed, you can use the == or === operators. Have a look at the comparing objectssection of PHP's documentation.
如果您只关心对象是否已更改,则可以使用 == 或 === 运算符。查看PHP 文档的比较对象部分。
That said, wouldn't just be easier to keep track of what you've changed as you change them?
也就是说,在更改更改时跟踪更改的内容会更容易吗?
回答by johnnietheblack
There is a whole site on php.net only dealing with comparing objects:
php.net 上有一个完整的站点只处理比较对象:
http://php.net/manual/en/language.oop5.object-comparison.php
http://php.net/manual/en/language.oop5.object-comparison.php
Also a good read:
还有一个很好的阅读:
http://www.tuxradar.com/practicalphp/6/12/0
http://www.tuxradar.com/practicalphp/6/12/0
I would say you should use the "clone" method when copying your object and then later compare as said in the php.net article.
我会说你应该在复制对象时使用“克隆”方法,然后按照 php.net 文章中的说明进行比较。
Also a fast way would be by declaring a static method in the class that just compares the relevant "properties" like lets say "username", "password", "cookie",...
还有一个快速的方法是在类中声明一个静态方法,它只比较相关的“属性”,比如“用户名”、“密码”、“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
}
};
回答by Gras Double
Here is a piece of code that supports private properties:
这是一段支持私有属性的代码:
$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 {
// ...
}
}
Note that if $object_1
has properties that $object_2
doesn't have, the above code will produce errors when trying to access them.
请注意,如果$object_1
具有$object_2
不具有的属性,则上述代码在尝试访问它们时会产生错误。
For such a case, you would need first to intersect $reflection_1->getProperties()
with
$reflection_2->getProperties()
.
对于这种情况,您首先需要$reflection_1->getProperties()
与
$reflection_2->getProperties()
.
回答by Jan Galtowski
Simple example comparing dto class through reflection
通过反射比较 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;
}
}