15

I want to know how to array_intersect for object array.

2
  • 1
    What do you mean by "object array" - do you mean an array of objects? Commented May 14, 2010 at 13:59
  • yes, that is array of objects. Commented May 14, 2010 at 14:09

8 Answers 8

19

You can use array_uintersect in conjunction with spl_object_hash, see an example:

    array_uintersect($a, $b, function($a, $b) {
        return strcmp(spl_object_hash($a), spl_object_hash($b));
    });

where '$a' and '$b' are arrays of some objects that you want to intersect.

Sign up to request clarification or add additional context in comments.

2 Comments

Nice solution. For contemporary readers: in php7, the strcmp() can be replaced with the <=> operator, like this: return spl_object_hash($a) <=> spl_object_hash($b);
Looking for that. Good solution. You can also use array_uintersect($a, $b, array($this, 'your_class_method')), in case you want to refer to a method in your class !
7

nice toString function is already implemented and is called serialize ;) so

array_map(
    'unserialize',
    array_intersect(
        array_map(
            'serialize',
            $obj1
        ), 
        array_map(
            'serialize', 
            $obj2
        )
    )
);

will do the work, example mentioned higher don't work 'cause array_intersect work's only with strings as someone mentioned too

1 Comment

on further thought, this isn't adequate if the objects have methods. when you serialize, you lose the methpds, so only properties are preserved
2

array_intersect() returns an array containing all the values of array1 that are present in all the arguments.

Then what mean present in this context (exacly this function), i found on php.net my answer:

Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same.

Then you can't use it on array of objects if your objects not implements unique conversion to string.

2 Comments

That's innacurate. There are at least three ways objects can be converted into a string. They may be a PHP class and implement __toString, they may have a cast handler that accepts IS_STRING and they may have a get handler that returns a zval that is convertable to a string.
+1 @Artefacto, submit an answer with an example using arbitrary objects and array_intersect().
2

Had a similar problem a few days ago, while these are answers are on the right path; I used them to work out the following:

From Artefacto's answer return $obj1 == $obj2 didn't really work, so I wrote a simple comparative function (basically gets the md5 of the serialised object and compares that):

function object_compare($obj1, $obj2){
  $md5 = function($obj){
    return md5(serialize($obj));
  };
  return strcmp($md5($obj1), $md5($obj2));
}

Then it’s jut a matter of calling array_uintersect with our comparative function to get the intersection:

# $array1 / $array2 are the array of objects we want to compare
return array_uintersect($array1, $array2, 'object_compare');

In my case, I had an unknown / dynamic array of objects, so I took it a step further so I don't have to declare array_uintersect($array1, $array2, ...) specifically - but just be able to pass in an array of arrays (of objects):

# $multiarray_of_objects is our array of arrays
$multiarray_of_objects[] = 'object_compare';
return call_user_func_array('array_uintersect', $multiarray_of_objects);

Just gotta remember to pass in the reference to our callback / comparative function as the last string in the array. Works like a charm!

2 Comments

Due to working inside a controller class, I could not quite do it like this, but using your approach with Artefacto's format worked like a charm.
In a class return array_uintersect($array1, $array2, 'self::object_compare'); should work, or even ClassName::object_compare, but remember it needs to be a public class function then.
1

The correct way to check whether two objects are equal is to use ==. Therefore:

array_uintersect($arr1, $arr2, function ($a1, $a2) { return $a1 == $a2; });

2 Comments

You'll have to be more specific. What doesn't work? Are there any error messages? What error messages? The ouput is not the expected? What was expected? What did you get?
This doesn't work because array_unintersect needs the comparison function to return 1, -1, or 0. See here for a full explanation and example php.net/manual/en/function.array-uintersect.php#72841
1

Just for completeness: Implement __toString() method in your object returning a unique value. For database entities this might be as easy as returning the fully qualified class name postfixed with the ID of the record. But it can also be arbitrarily complex by doing some hashing or even worse things.

In my opinion, it's the class's duty to serialize itself or create something unique to compare its objects by. Using anything outside of a class to serialize an object might result in strange behaviour (including comparing objects of different classes, which must never result in equality).

Comments

0

I use array_udiff to implement array_intersect for an object array.

 function diff($a, $b) {
 if($a === $b) {
     return 0;
 } else {
     return 1;}
 }

 $array_1 = array('a', 'b', 'c');    

 $array_2 = array('c', 'd','e');    

 $array = array_udiff($array_1, array_udiff($array_1, $array_2, 'diff'),'diff');

var_dump($array);
return array(1) { [2]=> string(1) "c" }

You can have your own diff function for any scheme.

Comments

-2

The correct solution would be:

array_uintersect($arr1, $arr2, function ($a1, $a2) { return $a1 != $a2; });

Note the != in the callback function as opposed to the answer from @Artefacto. Based on the documentation of array_uintersect, the callback function has to return 0 (false) if array items are equal.

1 Comment

This is an unnecessary type hack, the callback function should return integer (-1, 0, 1) if the first value is less than, equal or greater than the second, like for sorting functions. The implicit typecast of false to 0 will confuse readers of your code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.