0

I am trying to loop through a directory and only show files, no folders. I have come across this code from another person on SO, and while it works, I do not understand how.

function scandir_nofolders($d) {
    return array_filter(scandir($d), function ($f) use($d) {
       return ! is_dir($d . "/" . $f);
   });
}

So assume I have running this with the following code:

print_r(scandir_nofolders('/xampp');

Where I struggle is the inner most return value when the is_dir() function is determining whether the supplied parameter is a directory or not.

You'd think the code would translate to

return ! is_dir('/xampp'./.'/xampp');

Notice how in the above example $d and $f are the same. If you call an anonymous function and use the use function with in this case $d, wouldn't $d and $f be the exact same, because $f is essentially copying what $d is? Obviously I am not looking for /xampp//xampp (which is what I think the code would translate to), yet this works perfectly. Could someone explain what this code is actually doing? I imagine if anything, I have the true purpose of the use() function misunderstood.

user3412869
  • 1,395
  • 2
  • 10
  • 11

2 Answers2

0

They are not the same:

$d - is directory you pass for scandir_nofolders as argument (in your case '/xampp'

$f - is a single item in this directory (file, directory, . or ..)

To make a check you can simply add echo to this function:

function scandir_nofolders($d) {
    return array_filter(scandir($d), function ($f) use($d) {
       echo $d.' '.$f."<br />";
       return ! is_dir($d . "/" . $f);
   });
}

and you will see the difference.

In closures, closure argument is the element on which you want to make an operation (for example sorting, or in your case displaying/checking item) and in use you can add other variables as in your case you need to pass directory in which those item (files) are placed to make check using is_dir function

Marcin Nabiałek
  • 109,655
  • 42
  • 258
  • 291
  • But if `d` is the directory, when you call `function($f)`, `use($d)`, doesn't that just substitute $f for $d? – user3412869 Jul 16 '14 at 13:29
  • @user3412869 No, $d will have all the time `/xampp` value, and `$f` could be also directory name but inside `/xampp` folder so for example `scripts` but they are never the same. Have you run this code with echo? I think this explains everything. – Marcin Nabiałek Jul 16 '14 at 13:33
0

If you happen to know Javascript, the equivalent code there would be:

function scandir_nofolders(d) {
    return scandir(d).filter(function (f) {
       return !is_dir(d + "/" + f);
   });
}

What's happening here? The innermost is_dir call uses a concatenation of d and f. d is the same d as was passed into the function, f is the value of one element in the array returned by scandir. In Javascript, variables of the parent scope of a function are available just like that inside a function.

In PHP, that is not the case.

$d = 'foo';
function () {
    // no access to $d here
}

To make $d available inside the anonymous function, you need to "pass it through" using use. $d will be the parent directory and $f will be an entry within that directory.

Also see Reference: What is variable scope, which variables are accessible from where and what are "undefined variable" errors?

Community
  • 1
  • 1
deceze
  • 510,633
  • 85
  • 743
  • 889