PHP中的in_array对象比较?

32

函数in_array能否比较对象?

例如,我有一个对象数组,并且我想将它们独立地添加到另一个数组中。是否可能像这样检查对象是否已经被添加:

in_array($distinct, $object);

还有其他方法吗?


你对“distinct”的定义是什么?如果“distinct”是指引用不相等的相反,则将true作为第三个参数传递即可。 - Jon
这个可以用于数组中的对象吗? - gorgi93
1
对于“工作”的某些定义。您需要提供更多细节,心灵阅读很困难。 - Jon
2
类似问题的答案对您有帮助吗? - Furgas
什么是“distinct”?你想要什么不太清楚。 - Muhammad
8个回答

36
您可以使用严格比较:
in_array($object, $array, TRUE);

使用示例:

$a = new stdClass();
$a->x = 42;

$b = new stdClass();
$b->y = 42;

$c = new stdClass();
$c->x = 42;

$array = array($a,$b);

echo in_array($a, $array, true); // 1
echo in_array($b, $array, true); // 1
echo in_array($c, $array, true); //

由于问题的广泛性,我想补充一点:当您想从不同类中查找任何对象时,这是行不通的。只有通过严格比较找到完全相同实例的对象才能运作。 - Daan

17

in_array 函数无法比较对象。

您应该从对象中创建唯一的键值对,并且只需要在将新对象插入到最终数组时比较这些键。

假设每个对象都有一个唯一的 id 属性,可能的解决方案是:

$unique_objects = array();

// $data represents your object collection
foreach ($data as $item) {
    if (!array_key_exists($item->id, $unique_objects)) {
        $unique_objects[$item->id] = $obj;
    }
}

笑,什么?$idem 在任何地方都不是一个变量,$obj 也不是?这怎么被投票赞了13次? - Kristofer Doman
好的,我已经更新回应来修复$idem拼写错误。这个示例代码的假设是$obj只是表示需要唯一添加到$unique_objects数组中的一个现有变量。 - ukliviu
1
当然,in_array可以严格意义上比较对象。这个答案应该被取消接受并删除,因为它陈述了错误的信息。 - DonCallisto

6

我进行了一些测试,比较了使用in_array函数的对象。这是我的结论:

当您尝试在数组中查找同一个实例的对象(如OP)时,in_array可以使用严格的比较布尔设置。

当您尝试查找同一类但实例不同的任何对象时,in_array会显示出不符合直觉的行为。

PHP.net上有一个关于反直觉边缘案例的好用户评论

// Example array

$array = array(
    'egg' => true,
    'cheese' => false,
    'hair' => 765,
    'goblins' => null,
    'ogres' => 'no ogres allowed in this array'
);

// Loose checking -- return values are in comments

// First three make sense, last four do not

in_array(null, $array); // true
in_array(false, $array); // true
in_array(765, $array); // true
in_array(763, $array); // true
in_array('egg', $array); // true
in_array('hhh', $array); // true
in_array(array(), $array); // true

// Strict checking

in_array(null, $array, true); // true
in_array(false, $array, true); // true
in_array(765, $array, true); // true
in_array(763, $array, true); // false
in_array('egg', $array, true); // false
in_array('hhh', $array, true); // false
in_array(array(), $array, true); // false

如您所见,如果没有严格检查,测试 4 - 7 的in_array就毫无意义。

我们从 PHP.net 了解到,只有在严格比较(===)时,两个对象才相同,当它们来自同一类+实例。当两个对象来自同一类时,它们在松散比较(==)中已经是相同的。

我编写了一些对象测试来看看会发生什么。

$a = new stdClass();                              
$a->egg = true;                                   

$b = new stdClass();                              
$b->cheese = false;                               

$c = new stdClass();                              
$c->hair = 765;                                   

$d = new stdClass();                              
$d->goblins = null;                               

$e = new stdClass();                              
$e->ogres = 'no ogres allowed in this array';     

$array2 = array($a, $b, $c,  $d, $e);         

$e = new stdClass();                                            
$e->egg = null;                                                 

$f = new stdClass();                                            
$f->egg = false;                                                

$g = new stdClass();                                            
$g->egg = 765;                                                  

$h = new stdClass();                                            
$h->egg = 763;                                                  

$i = new stdClass();                                            
$i->egg = 'egg';                                                

$j = new stdClass();                                            
$j->egg = 'hhh';                                                

$k = new stdClass();                                            
$k->egg = array();                                              

in_array($e, $array2, false); // false                
in_array($f, $array2, false); // false                
in_array($g, $array2, false); // true                 
in_array($h, $array2, false); // true                 
in_array($i, $array2, false); // true                 
in_array($j, $array2, false); // true                 
in_array($k, $array2, false); // false                

in_array($e, $array2, true); // false                 
in_array($f, $array2, true); // false                 
in_array($g, $array2, true); // false                 
in_array($h, $array2, true); // false                 
in_array($i, $array2, true); // false                 
in_array($j, $array2, true); // false                 
in_array($k, $array2, true); // false 

在最后的检查中,in_array 的第3至6个检查结果与预期相反。
原因如下:如果你尝试按某个值查找任何对象,你必须使用宽松比较(因为当类不同时,严格比较总是失败的)。但由于PHP变量类型的缘故,在最后的测试中,这些检查被认为是true,因为该值被认为是truthy。另外请注意,在宽松比较中忽略了对象上的键。

3

您可以看到有很多种方法可以做到这一点。我只是想再添加一个。我不知道为什么,但在使用对象数组时,我喜欢使用使用回调的数组函数。

如果您的对象具有任何形式的标识符(如果您想要测试它们是否重复),则以下内容将起作用:

$found = array_filter($uniqueObjects, function($uniqueObject) use ($object) {
    return $uniqueObject->id == $object->id
});

if (!$found) {
    $uniqueObjects[] = $object;
}

$object是您要查找的对象,$uniqueObjects是您正在搜索以查看其是否存在的对象数组。只需在识别属性上匹配uniqueObject和object,例如id


3

1

我不知道是不是因为PHP版本更新的原因,但在我的项目中,使用Ubuntu 12.04上的PHP 5.3.16,它可以工作。它在对象数组中找到了针对象。我还通过加载同一类的另一个对象并将其与未包含该对象的数组内容进行测试进行了双重检查,结果确实返回了false。

所以,是的,in_array可以比较对象。


0
如果“STRICT”为“FALSE”,则通过将元素转换为字符串进行比较。因此,如果您覆盖__toString魔术函数,则应该可以比较对象元素。

0

我想出了一个有些不同的、更加健壮的选择。

function array_add_unique(&$array, $new, $test, $cb) {
  if(is_array($array) && count($array)>0) {
    for($i = 0; $i < count($array); $i++) {
      if( $array[$i][$test] == $new[$test] ) {
        $do = $cb($array[$i], $new);
        if(is_bool($do) && $do) { $array[$i] = $new; }
        else if(!is_bool($do)) { $array[$i] = $do; }
        return;
      }
    }
  }
  array_push($array, $new);
}

这种解决方案的好处是它包括一个用户可定义的回调函数来处理碰撞。当您添加唯一对象时,您可能希望保留旧对象和新对象的属性。

回调函数可以是匿名函数,接收新对象和现有对象,以便用户可以进行自定义计算。返回true以简单地替换现有对象,或者返回一个新对象(非布尔值)以替换它。

我不知道在大型数据集上的性能如何。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接