PHP in_array object comparing?
I did some tests comparing objects with the in_array
function. This is my conclusion:
When you try to find the same instance of an object in an array (like OP), then in_array
could work with the strict comparison boolean set.
When you try to find any object of the same class but with a different instance, in_array
shows counter-intuitive behavior.
There is a great user comment on PHP.net about the counter-intuitive edge cases.
// 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
As you can see that without strict checking the in_array
tests 4 - 7 don't make sense.
We know from PHP.net that two objects are only the same in strict comparison (===
) when they are from the same class + instance. Two objects are already the same in loose comparison (==
) when they are from the same class.
I wrote some tests with objects to see what happens.
$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 the last checks in_array
checks 3 - 6 give counter-intuitive results.
The reason is as follow. If you try to find any object with a certain value, you are forced to use loose comparison (because when the class is not the same, strict comparison always fails). But due to PHP's variable types, in the last tests these checks are considered true, because the value is considered truthy. Also note that the key on the object is ignored in loose comparison.
The in_array function cannot compare objects.
You should create unique key-value pairs from your objects and only need to compare those keys when inserting a new object into your final array.
Assuming that each object has an unique id
property, a possible solution would be:
$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;
}
}
See 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;
}
Cheers
You can use strict comparison:
in_array($object, $array, TRUE);
Usage example:
$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); //