该in_array
函数可以比较对象吗?
例如,我有一个对象数组,我想将它们明确地添加到另一个数组中。是否可以像这样检查对象是否已经添加:
in_array($distinct, $object);
还是有其他方法?
该in_array
函数可以比较对象吗?
例如,我有一个对象数组,我想将它们明确地添加到另一个数组中。是否可以像这样检查对象是否已经添加:
in_array($distinct, $object);
还是有其他方法?
您可以使用严格比较:
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); //
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;
}
}
我做了一些比较对象和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
如您所见,如果不严格检查in_array
测试 4 - 7 是没有意义的。
我们从 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 的变量类型,在最后的测试中,这些检查被认为是真实的,因为该值被认为是真实的。另请注意,在松散比较中忽略对象上的键。
见http://php.net/manual/en/function.spl-object-hash.php
if ( ! array_key_exists( spl_object_hash( $obj ), $objects ) ) {
$objects[ spl_object_hash( $obj ) ] = $obj;
}
干杯
如您所见,有很多方法可以做到这一点。我只是想我会添加另一个。我不知道为什么,但是在使用对象数组时,我喜欢使用使用回调的数组函数。
如果您的对象有任何类型的标识符,如果您想测试它们是否重复,它们应该有,以下将起作用:
$found = array_filter($uniqueObjects, function($uniqueObject) use ($object) {
return $uniqueObject->id == $object->id
});
if (!$found) {
$uniqueObjects[] = $object;
}
$object
是您正在寻找的对象,并且$uniqueObjects
是您正在搜索以查看它是否存在的对象数组。只需在标识属性上匹配 uniqueObject 和 object,例如id
.
我不知道是不是因为 PHP 版本较新,但在我的项目中,在 Ubuntu 12.04 上使用 PHP 5.3.16,它可以工作。它在我的对象数组中找到了 needle 对象。我还通过加载同一类的不同对象进行了双重检查,并针对不包含该对象的数组内容对其进行了测试,结果确实返回了 false。
所以是的,in_array
可以比较对象。
如果“STRICT”为“FALSE”,则通过将元素转换为字符串来进行比较。因此,如果您覆盖 __toString 魔术函数,您应该可以比较对象元素。
我想出了一个有点不同的,我认为更强大的选项。
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以简单地替换现有对象,或返回一个新对象(非布尔型)来替换它。
不过,我不知道它在大型数据集上的性能。