create_functionでテンプレート

最近,

if(!is_dir($dir)) return false;
if($hd = opendir($dir)){
  while(false !== $file = readdir($hd)){
    if($file != "." && $file != ".."){
      if(!is_dir($dir."/".$file)){
        ・・・・・・・
      }
    }
  }
  closedir($hd);
}

とか,

if(!is_dir($dir)) return false;
if($hd = opendir($dir)){
  while(false !== $file = readdir($hd)){
    if($file != "." && $file != ".."){
      if(is_dir($dir."/".$file)){
        ・・・・・・・・・・・
      }
      else{
        ・・・・・・・・・・・
      }
    }
  }
  closedir($hd);
}

みたいなことを書くことが多いのだけど, 最初の4行がめんどくさい。
コピペするのもめんどくさい。Rubyだとブロックを使えば簡単に解決できそうだが,
PHPなのでcreate_functionで無名関数を放りこんでテンプレートを作成。

//指定したディレクトリを読み込んで読み込んだのがファイルなら引数の関数を実行する
function exeOnlyFile($dir, $f, $arg=null){
  
  if(!is_dir($dir)) return false;

  if($hd = opendir($dir)){
    while(false !== $file = readdir($hd)){
      if($file != "." && $file != ".."){
        if(!is_dir($dir."/".$file)){
	  $f($file, $arg);
	}
      }
    }
    closedir($hd);
  }
  return $arg;
}

//指定したディレクトリを読み込んでエントリがファイルかディレクトリかで処理を振り分ける
function divDirOrFile($dir, $if_f, $else_f, $arg=null){
  
  if(!is_dir($dir)) return false;

  if($hd = opendir($dir)){
    while(false !== $file = readdir($hd)){
      if($file != "." && $file != ".."){
        if(is_dir($dir."/".$file)){
          $if_f($dir,$file,$arg);
    	}
    	else{
          $else_f($dir,$file,$arg);
        }
      }
    }
    closedir($hd);
  }
  return $arg;
}

例えば↓のような時に適用する。

//指定したディレクトリにあるファイルの数を返す
function getFileNum($dir){

    $n = 0;
    if(!is_dir($dir)) return false;

    if($hd = opendir($dir)){
        while(false !== $file = readdir($hd)){
            if($file != "." && $file != ".."){
                if(!is_dir($dir."/".$file)){
                    $n++;
                }
             }
        }
        closedir($hd);
    }
    return $n;
}

//指定したディレクトリ配下のファイルを配列で取得する
function getFiles($dir){

    if(!is_dir($dir)){
        return false;
    }
    
    $files = array();
    if($hd = opendir($dir)){
        while(false !== $file = readdir($hd)){
            if($file != "." && $file != ".."){
               if(!is_dir($dir."/".$file)){
                    $files[] = $file;
                }
            }
        }
        closedir($hd);
    }
    return $files;
}

//指定したディレクトリ以下の全てのディレクトリ, ファイルを削除
function deleteRecursive($dir){

    if(!is_dir($dir)){
        return false;
    }

    $dirs = array();
    if($hd = opendir($dir)){
        while(false !== $file = readdir($hd)){
            if($file != "." && $file != ".."){
                if(is_dir($dir."/".$file)){
                    array_unshift($dirs, $dir."/".$file);
                    deleteRecursive($dir."/".$file);
                }
                else{
                    unlink($dir."/".$file);
                }
            }
        }
        closedir($hd);
    }
    while($d = array_shift($dirs)){
        rmdir($d);
    }
    rmdir($dir);
}

さっきの関数を使うとかなり簡単に書ける。

//指定したディレクトリ配下のファイルを配列で取得する
function getFiles($dir){
  $f = create_function('$file,&$files', '$files[] = $file;');
  return exeOnlyFile($dir, $f, array());
}

//指定したディレクトリにあるファイルの数を返す
function getFileNum($dir){
  $n = 0;
  $f = create_function('$dummy,&$n', '$n++;');
  return exeOnlyFile($dir, $f, $n);
}

//指定したディレクトリ以下の全てのディレクトリ, ファイルを削除
function deleteRecursive($dir){

  $if_f = create_function('$dir,$file,&$dirs','array_unshift($dirs,$dir."/".$file);'.
                                              'deleteRecursive($dir."/".$file);');

  $else_f = create_function('$dir,$file,$dummy', 'unlink($dir."/".$file);');
  $dirs = divDirOrFile($dir, $if_f, $else_f, array());
    
  while($d = array_shift($dirs)){
    rmdir($d);
  }
  rmdir($dir);
}

渡せる引数が1個だけなのが欠点だけど結構使える。