我正在寻找一种方法来生成某种PHP对象的散列(通用解决方案,与所有类,内置和自定义,如果可能的话)。
SplObjectStorage::getHash不是我想要的,因为它会为给定类的每个示例生成不同的哈希。为了描述这个问题,让我们考虑简单的类:
class A() {
public $field; //public only for simplicity
}
和该类的2个示例:
$a = new A(); $a->field = 'b';
$b = new A(); $b->field = 'b';
我尝试过的每个内置函数都会为这些对象返回不同的哈希值,而我希望有一些带有f($a) == f($b) => $a == $b
属性的function f($x)
。
我知道我可以写一个函数,递归地遍历所有对象的属性,直到我找到一个可以转换为字符串的属性,以花哨的方式连接这些字符串并哈希,但这样的解决方案的性能将是可怕的。
有没有一个有效的方法来做到这一点?
3条答案
按热度按时间omhiaaxx1#
假设我理解正确,你可以序列化对象,然后md5序列化对象。由于序列化创建相同的字符串,如果所有属性都相同,你应该每次都得到相同的哈希值。除非你的对象有某种时间戳属性。示例:
输出:
你的结果不同,因为php内存中的对象是用每个示例化的编号id存储的:
jfewjypa2#
你似乎在谈论一个值对象。它是一种模式,其中每个这样的对象不是根据对象标识进行比较,而是关于组成对象的全部或部分属性的内容。
我在一个项目中使用了其中的一些:
更复杂的对象可以简单地将更多项添加到比较函数中。
这样的条件句(都是用“&&”连接的)一旦有任何项不匹配,就会被快捷方式转换为false。
vsikbqxv3#
实际上,这个问题提出了两个可能相互矛盾的问题。
1.一种以一致(且高性能)的方式散列任何对象的方法。
1.使用此散列方法对对象进行有效比较。
首先,哈希。其他人出于性能原因建议使用
serialize()
,但它确实引入了一个限制:PHP对象可以在外部添加字段,也可以在类中声明字段。因此,有可能(尽管不太可能,而且肯定是有问题的编码实践的指示),您的对象可以具有相同的字段,但以不同的顺序声明。这将产生不同的序列化,根据您的问题的措辞,您不希望这样。为了防止这种情况,你需要将对象转换为数组并对其成员进行排序。如果任何字段本身就是对象或数组,可能会有同样的问题,你应该递归地工作。
这提供了可以序列化和哈希的对象的一致表示。或者,您可以在函数本身中实际构建哈希:
json_encode()
可以用来代替var_export()
,但我选择后者是为了保证PHP值的忠实表示(JSON中可能会发生冲突,我不知道),我怀疑它可能会表现得更好。如果一个对象包含循环引用,例如,它有一个对象或数组字段包含一个值,该值是对它的引用?
serialize()
可以处理这种情况;上面的功能不能。现在:比较。最好的方法是由 * 答案最有可能是什么 * 来决定。也就是说:
如果您期望正在比较的大多数对象对都不同,那么逐段比较它们会更有效,这样您就可以尽快建立差异。
如果你希望大多数对都匹配,那么你也可以对每个对象进行完整的哈希,然后比较它们(如果使用
serialize()
,这可能比使用上面的递归函数更有效),因为无论如何,在每个示例中,你都没有找到答案的捷径。