dalecosp between v1 and v2 you changed from popping to shifting the $queues array. Any particular reason for that?
Um, nope. No particular reason on correctness grounds - it's just the difference between a depth-first (pop) and a breadth-first (shift) search. (besides: you shift a queue but pop a stack! I couldn't make up my mind.) Popping would be "faster" because the queue wouldn't need reindexing, but the slow part is actually unlinking the directory. Note the comment in the original code about Windows. Going breadth-first (especially on broad flat directory tree structures) would make the situation in that comment less likely to occur with the code as it stood then. But it doesn't happen with the later code and I'm not entirely sure why that should be (though I do have suspicions).
[Edit: realised I never mentioned another difference I found. On one large tree, using depth-first traversal the stack got up to 12,752 items long; breadth-first on the same tree, 154,163. So that's a difference worth noting.]
But that first version is way more complicated than it needed to be: I don't need a two-part "traverse then prune" (with a sort in between) process because the nature of the traversal means that I never end up planning to remove parent directories before their children anyway. (Since the first pass always goes "visit parent, visit child" and the second "remove child, remove parent", I can have just the one pass going "visit parent, visit child, remove child, remove parent").
Just as a rough guide to what's going on in the later versions:
The queue is an array of array of directory names (realpath()ed to ensure the traversal doesn't wander off and get lost). It could just be an array of directory names, and then the double loop would be a single loop, but that queues[] = ...
would become an array_merge and PHP would end up copying and recopying it over and over and over (array_merge loops are slow).
As a queue it's plain enough: If directory $d
has child directories then they go on the queue. If it's empty (neither child directories nor files) then the innermost loop there kicks in. I go up to $d
's parent from where I can safely remove $d
(fun fact: you can rmdir('.')
but you probably shouldn't), and make the parent the new $d
in case we just removed its last child.
The feedback is just a line showing the current directory that scrolls each time one is removed to produce a list of removed directories.