2
\$\begingroup\$

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

\$\endgroup\$
4
+50
\$\begingroup\$

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.

\$\endgroup\$
  • \$\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 Oct 14 '14 at 22:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.