Salathe's solution works on a couple of the quirks (if you want to call them that) or methods of how array_intersect and array_diff work (moreso the former).
Array_Intersect takes multiple arguments in the form of arrays; It then intersects each array in turn with the initial array, to give a result array. Due to the way this function works, it will always check the first item of the array first (as defined by an array-shift; not by key value. Think of it like doing a FOREACH on the array), then the second. Thus by defining "massive" as the first element of the match-against array, you effectively prioritize it in the array_intersect, because it will search for "massive" first, then "big". It's an iterative construction. Note that you would NOT have gotten the same result if you'd array_intersected with the parameters the other way around!
Array_diff does the same thing but in reverse; it finds everything that is in the initial array that isnt in the secondary. Again, order (and keys) is preserved; so the 'remainder' remains in the same order as when it went in (and missing any keys for which it had a deleted value) because of the order in which the parameters are given. The secondary ('input') array is first in the parameter list, so it defines the order of the output.
So now you have two complimentary arrays (the intersected, or matched values, in order of the $priorities, and the diffed, or unmatched, in the original order).
Array_merge takes the second array, plops it on the end of the first array. In this way you have prioritized the values you wanted to prioritize, in the order you wanted to prioritize them; the rest of the data you didnt care about, so it's just stuck on the end, unsorted.
If this is still unclear let me know.