【发布时间】:2020-09-06 16:32:47
【问题描述】:
我似乎无法弄清楚 PHP 场景背后发生了什么魔力,以及为什么 array_unique 无法检测到我的重复项。
在我的具体情况下,我有 2 个用户集合,我将它们合并为一个,然后只保留唯一的条目。为此,我将两个集合都转换为数组,array_merge() 它们,然后基于参数应用 array_unique(..., SORT_REGULAR),以便将它们作为对象进行比较,无需任何转换。我意识到比较对象是一个滑坡,但在这种情况下它比我更奇怪。
如您所见,第 4 项和第 11 项是同一个用户实体(非严格比较和严格比较都同意这一点)。然而,在array_unique() 之后,由于某种原因,它们都保留在列表中:
如您所见,项目 7-10 被检测并删除,但 11 没有。
这怎么可能?我在这里没有看到什么?
当前运行 PHP 7.4.5
代码来自使用 Symfony 4.4.7 和 Doctrine ORM 2.7.2 的项目(尽管我认为这应该是无关紧要的,如果对象通过 == 和 === 比较相等)。
关于奖励积分的有趣事实 - 连续两次应用 array_unique 会产生独特的结果:
头脑 = 炸毁
更新:我在User::__toString() 方法中添加了throw new \RuntimeException(),以确保没有人正在转换为字符串。
请不要建议转换为字符串 - 这既不是我的问题的解决方案,也不是这个问题的意义所在。
【问题讨论】:
-
@u_mulder - 您能否详细说明“仍然不应该为此设置 array_unique”?为什么不呢?
-
array_unique 比较字符串。所以检查比较对象字符串表示(字符串)$a ===(字符串)$b
-
看起来代码创建了返回值数组(在需要的地方转换为字符串 - 请参阅上转换)并使用第二个数组按索引删除元素以进行比较(代码中的
arTmp)。第二个数组使用 pointers 指向变量(请参阅cmpdata->b.val,其中 b 是指针,因此 b.val 不是字符串表示形式)来查找要删除的内容。这有效,因为所有内容都被索引删除。至于您第二次调用该函数,它可以工作,因为这次您传入的是字符串,因为这是第一个函数返回的内容。 -
documentation 中实际上有一个非常明确的警告:“对具有混合类型值的数组进行排序时要小心,因为如果 sort_flags 为 SORT_REGULAR,sort() 会产生意外结果”
-
@Marvin 谢谢,我自己还没有看到这个警告(主要是因为我正在研究 array_unique 并且直到昨天才意识到排序在那里起着重要作用。我会说你的这个评论关于手头整个问题的 50%
标签: php