【问题标题】:PHP - hash objects in a way distint object with same fields values have same hashPHP - 以某种方式散列对象,具有相同字段值的不同对象具有相同的散列
【发布时间】:2015-10-17 23:57:42
【问题描述】:

我正在寻找一种为 PHP 对象生成某种散列的方法(通用解决方案,如果可能,使用所有分类、内置和自定义)。

SplObjectStorage::getHash 不是我想要的,因为它会为给定类的每个实例生成不同的哈希。为了描述这个问题,让我们考虑一个简单的类:

class A() {
public $field; //public only for simplicity
}

以及该类的 2 个实例:

$a = new A(); $a->field = 'b';
$b = new A(); $b->field = 'b';

我尝试过的每个内置函数都会为这些对象返回不同的哈希值,而我想要一些 function f($x) 和属性 f($a) == f($b) => $a == $b

我知道我可以编写一个递归遍历所有对象属性的函数,直到找到一个可以转换为字符串的属性,以奇特的方式连接这些字符串并散列,但是这种解决方案的性能会很糟糕。

有没有一种有效的方法来做到这一点?

【问题讨论】:

    标签: php performance hash


    【解决方案1】:

    假设我理解正确,您可以序列化对象然后 md5 序列化对象。由于如果所有属性都相同,则序列化会创建相同的字符串,因此您每次都应该获得相同的哈希值。除非您的对象具有某种时间戳属性。示例:

    class A {
        public $field;
    }
    $a = new A;
    $b = new A;
    $a->field = 'test';
    $b->field = 'test';
    echo md5(serialize($a)) . "\n";
    echo md5(serialize($b)) . "\n";
    

    输出:

    0a0a68371e44a55cfdeabb04e61b70f7
    0a0a68371e44a55cfdeabb04e61b70f7
    

    你的结果不同,因为 php 内存中的对象存储有每个实例化的编号 id:

    object(A)#1 (1) {...
    object(A)#2 (1) {...
    

    【讨论】:

    • 当然,internally 这完全符合 OP 的建议:“递归遍历所有对象的属性……转换为字符串,连接……以奇特的方式”。但是这种方式将比尝试在用户空间中实现所有这些更有效且更不容易出错。 :)
    • 啊,好点。我没有考虑到这一点。我在想他的意思是必须编写一个函数来遍历它。
    • 明确地说,我认为序列化可能是正确的解决方案,并投票支持您的答案。最终,任何需要比较两个深层结构的值的东西都必须递归地检查这些结构——无论是serializevar_dump,还是手动堆栈和循环。即使使用原始内存访问,您也需要递归地跟踪指向其他内存区域的指针。同样,任何需要散列数据结构的东西都必须首先将其展平为标准字节表示,因此也无法避免字符串转换。
    • 感谢您的回答@Robert Cathey。我确实在最后的手段考虑序列化。让我担心的是,除了这个解决方案的性能之外,有些对象无法根据php.net/manual/en/function.serialize.php 进行序列化。我不确定哪些是不可序列化的——我可能能够接受和/或为它们定义某种回退模式。
    • 我从未有过无法序列化的对象。该链接表示它处理除资源类型之外的所有变量类型,资源类型不包括对象。它是一种特殊类型的变量。老实说,我认为你不会有任何麻烦。
    【解决方案2】:

    您似乎在谈论一个值对象。这是一种模式,其中每个此类对象不是根据对象身份进行比较,而是根据内容 - 完全或部分组成对象的属性。

    我在一个项目中使用了其中的一些:

    public function equals(EmailAddress $address)
    {
        return strtolower($this->address) === strtolower((string) $address);
    }
    

    更复杂的对象可以简单地将更多项目添加到比较函数中。

    return ($this->one === $address->getOne() && 
        $this->two === $address->getTwo());
    

    因此,只要有任何项目不匹配,此类条件(均以“&&”连接)将快捷方式为 false。

    【讨论】:

    • 虽然这是真的,但它并没有回答当前框架的问题,它专门讨论散列,而不是直接比较,以及关于“通用解决方案,使用所有类,内置和自定义",而不仅仅是实现特定接口的类的子集。
    猜你喜欢
    • 2018-05-22
    • 1970-01-01
    • 2019-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2021-02-14
    相关资源
    最近更新 更多