For my application, I was using array_diff_assoc
, when I noticed it was returning the wrong value. I was using multidimensional arrays, therefore I needed a array_diff_assoc_recursive
method.
I Googled around and found a few, but they all only took 2 parameters. The official array_diff_assoc
can take an infinite number of params. I wanted mine to, so I wrote my own array_diff_assoc_recursive
function.
<?php
class Tools{
/**
* Recursive version of array_diff_assoc
* Returns everything from $a that is not in $b or the other arguments
*
* @param $a The array to compare from
* @param $b An array to compare against
* @param ... More arrays to compare against
*
* @return An array with everything from $a that not in $b or the others
*/
public static function array_diff_assoc_recursive($a, $b){
// Get all of the "compare against" arrays
$b = array_slice(func_get_args(), 1);
// Initial return value
$ret = array();
// Loop over the "to" array and compare with the others
foreach($a as $key=>$val){
// We should compare type first
$aType = gettype($val);
// If it's an array, we recurse, otherwise we just compare with "==="
$args = $aType === 'array' ? array($val) : true;
// Let's see what we have to compare to
foreach($b as $x){
// If the key doesn't exist or the type is different,
// then it's different, and our work here is done
if(!array_key_exists($key, $x) || $aType !== gettype($x[$key])){
$ret[$key] = $val;
continue 2;
}
// If we are working with arrays, then we recurse
if($aType === 'array'){
$args[] = $x[$key];
}
// Otherwise we just compare
else{
$args = $args && $val === $x[$key];
}
}
// This is where we call ourselves with all of the arrays we got passed
if($aType === 'array'){
$comp = call_user_func_array(array(get_called_class(), 'array_diff_assoc_recursive'), $args);
// An empty array means we are equal :-)
if(count($comp) > 0){
$ret[$key] = $comp;
}
}
// If the values don't match, then we found a difference
elseif(!$args){
$ret[$key] = $val;
}
}
return $ret;
}
}
I was wondering what you thought of my attempt. It seems to work ok for my application, and in the few tests I tried with it.
DEMO: http://ideone.com/5GZ8Tn
1 Answer 1
The logic looks good but I would like to suggest a few tips to enhance readability and maintainability of your code.
First off: name your variables accordingly $a
doesn't say anything to any random person when reading the code. He will have to scroll up and down figuring out what is what.
Second: Split your function into multiple methods. This will enhance readability and will keep an overview of your code. Now you have one very large method which will take a random person at least half an hour to figure out what it all does exactly.
Third: Try to avoid things like continue 2;
, break;
and more. They don't mean anything when you read code and can be avoided in most cases.
Fourth: Comments rot very quickly! Try and make sure that your methods are selfexplanatory so that you dont need to put comments.
-
1\$\begingroup\$ Suggestion 2 is good and makes suggestion 1 less important. Suggestion 3 is wrong - however you can use a break variable and check for it instead.. may be friendlier on the eye for people who can't see the level control your code used. Suggestion 4 is valid, sadly, but still put comments. \$\endgroup\$user56078– user560782014年10月14日 22:40:38 +00:00Commented Oct 14, 2014 at 22:40
array_diff_assoc_recursive
method. I don't think I am still working on the project that this was used in. Though, as you've shown the code does need a bit of work to do what it's supposed to do. Maybe if I am bored later, I can try to fix it. Whatever I was using this for, it seemed to be ok there, but I don't remember exactly what this was being used for :-) \$\endgroup\$array_diff_assoc
does, but then digs into arrays and compares individual elements using the samearray_diff_assoc
logic... \$\endgroup\$array_diff_assoc
say "the values from array1 that are not present in any of the other arrays." So, if it finds the value in any of the comparative arrays, it's removed from the first array. With myarray_diff_assoc_recursive
method if it sees an array as a value, it calls itself again. I'd think that your data should just be[8,10]
... \$\endgroup\$