再帰関数は、関数の中でその関数自身を呼び出す、ということを行っている関数です。将棋やチェスのようなゲームや、パズルを解くようなプログラムではよく使われ、プログラムをとてもシンプルに、見通しよく記述することができます。今回は、そんな再帰関数をPHPで使った例をご紹介します。

PHPでゲームを作る、というようなことはまずないと思うので、使いどころはか なり限られてしまうのですが、それでも便利に使える場面がないわけではありま せん。 ここではディレクトリ内のファイルをチェックし、そのディレクトリ内に含まれ るファイルサイズの合計を求めるプログラムを作ってみます。

ディレクトリに含まれるのが全てファイルなら、再帰関数でなくても大丈夫です が、ディレクトリ内が階層になっている場合は再帰関数が威力を発揮します。

<?php
//PHP4の場合、scandir関数がないので実装しておきます。
if (!function_exists(scandir)) {
  function 
scandir($dir_name$order '') {
    
$dh opendir($dir_name);
    while ( (
$filename readdir($dh)) !== false) {
      
$file_list[] = $filename;
    }

    if (
$order) {
      
rsort($file_list);
    } else {
      
sort($file_list);
    }
    return 
$file_list;
  }
}

//引数 $pathにはディレクトリ、またはファイルの絶対パスを指定。
function getDirSize($path) {
  
$total_size 0;

  
//指定したのがファイルだった場合はサイズを返して終了。
  
if (is_file($path)) {
    return 
filesize($path);

  } elseif (
is_dir($path)) {
    
$basename basename($path);

    
//カレントディレクトリと上位ディレクトリを指している場合はここで終了。
    
if ($basename == '.' || $basename == '..') {
      return 
0;
    }

    
//ディレクトリ内のファイル一覧を入手。
    
$file_list scandir($path);

    foreach (
$file_list as $file) {
      
//ディレクトリ内の各ファイルを引数にして、自分自身を呼び出す。
      
$total_size += getDirSize($path .'/'$file);
    }
    return 
$total_size;

  } else {
    return 
0;
  }
}


//関数を実行。
echo getDirsize('/home/asial');

?>

これだけで、指定したディレクトリ内のファイルサイズを求めることができます。

ただ、注意しないといけない点もあります。 少し間違えたり、思いがけない例外があった場合、無限ループに陥ってしまうこ とがあります。 上記のプログラムの場合、basename関数を使ってチェックを行わないと無限ルー プになります。また、指定したディレクトリ内にシンボリックリンクがある時も 無限ループになってしまう場合があるので気をつけて下さい。

再帰関数は、最初はとっつきにくく感じるかもしれませんが、一度理解して使い どころで使えるようになると、非常に便利なものです。 また、PHP以外のプログラミングの時にも使えますので、今までなじみの薄かっ た人もトライしてみてはどうでしょうか。



(アシアル 牧野克俊)


この記事は、アシアルが運営するPHP開発者のためのポータル&コミュニティサイト「PHPプロ!」で毎週配信しているPHP・TIPSメーリングリストを再録したものです。
同サイトでは、他にもPHP最新ニュースや、困ったときのQ&A掲示板、初心者向けのPHP講座など、PHP開発者をサポートする情報を掲載しています。