为什么 array_unique 不检测重复对象?

mki*_*nas 9 php

我似乎无法弄清楚 PHP 场景背后发生了什么魔法以及为什么array_unique无法检测到我的重复项。

在我的特定情况下,我有 2 个用户集合,我将它们合并为一个,然后只保留唯一的条目。为此,我将两个集合都转换为数组,array_merge()然后根据参数 applyarray_unique(..., SORT_REGULAR)将它们作为对象进行比较,而无需进行任何转换。我意识到比较对象是一个滑坡,但在这种情况下,它比我更奇怪。

合并后但在唯一性检查之前我有这个状态: 在此处输入图片说明

如您所见,第 4 项和第 11 项是同一个 User 实体(非严格比较和严格比较都同意这一点)。然而,array_unique()由于某种原因,他们都留在列表中之后: 在此处输入图片说明

如您所见,项目 7-10 被检测到并被删除,但 11 则没有。

这怎么可能?我在这里看不到什么?

当前运行 PHP 7.4.5

代码来自使用 Symfony 4.4.7 和 Doctrine ORM 2.7.2 的项目(尽管我认为这应该无关紧要,如果对象在比较=====比较时相等)。

奖励积分的有趣事实 -array_unique连续申请两次实际上会产生独特的结果: 在此处输入图片说明

头脑=吹

更新:throw new \RuntimeException()在我的User::__toString()方法中添加了,以确保没有人在进行字符串转换。

请不要建议转换为字符串 - 这既不是我的问题的解决方案,也不是这个问题的内容。

β.ε*_*.βε 2

对于您手头的问题,我真的怀疑这是来自 array_unique使用该标志时从数组中删除元素的方式SORT_REGULAR

  1. 排序
  2. 如果相邻项相等,则删除它们

Proxy而且因为您的集合中确实有一个对象User,所以这可能会导致您当前面临的问题。

这似乎得到了sortPHP 文档页面警告的支持,正如Marvin 的评论所指出的那样。

警告对具有混合类型值的数组进行排序时要小心,因为如果is sort(),可能会产生意外结果。sort_flagsSORT_REGULAR

来源:https ://www.php.net/manual/en/function.sort.php#refsect1-function.sort-notes


现在,对于一个可能的解决方案,这可能会给你带来更多 Symfony 风格的东西。

它使用ArrayCollection filtercontains方法来过滤第二个集合,并仅添加第一个集合中不存在的元素。
为了完整起见,该解决方案还利用了use语言构造,以便将第二个值传递ArrayCollection给 所需的闭包函数filter

这将产生一个ArrayCollection不包含重复用户的新用户。

public static function merge(Collection $a, Collection $b, bool $unique = false): Collection {
  if($unique){
    return new ArrayCollection(
      array_merge(
        $a->toArray(),
        $b->filter(function($item) use ($a){
          return !$a->contains($item);
        })->toArray()
      )
    );
  }

  return new ArrayCollection(array_merge($a->toArray(), $b->toArray()));
}
Run Code Online (Sandbox Code Playgroud)