👏

プログラミング・テクニック:再帰処理(再帰呼び出し)

2022/05/05に公開

再帰処理とは

ある関数内で、その関数を呼び出すことです。

この文だけだと意味が分かりませんが、実例を見ればすぐに分かると思います。

//  関数を定義
function add( $a, $b ){
  $a += $b;
  if( $a < 10 ){
    $a = add($a, $b); // ⬅️再帰呼び出し❗️
  }
  return $a;
}

//  関数を実行
echo add(1, 1);

これだけだと何が便利なのか分からないと思います。

実例

配列をtebleタグで表示するプログラムを作ります。これはデバッグでも役に立ちます。

配列をtableタグで出力する

error_reporting(E_ALL);
$arr = ['apple','google','microsoft'];
echo Table($arr);

//  ...
function Table($arr){
  $table = '<table style="border:1px solid black; border-collapse: collapse">';
  foreach( $arr as $i => $value ){
    $table .= '<tr>';
    $table .= "<th>{$i}</th><td>{$value}</td>";
    $table .= '</tr>';
  }
  $table .= '</table>';
  return $table;
}

実際に上記のソースコードを実行してみて下さい。上手く表示されたでしょうか?
上手く表示されたら次のステップに進んで下さい。

配列に、配列が含まれているとエラーになる

ただし上記では、配列に配列が含まれていると(二次元配列)変数の内容を表示できません。
具体的には、次のような配列はエラーになります。

$arr = ['apple','google','microsoft','os'=>['mac','android','windows']];
echo Table($arr);

理由は、変数が配列なのに、文字列として出力しようとしているからです。

二次元配列をサポートする

配列に配列が含まれている配列を二次元配列と言います。
もし配列に配列が含まれていたら、再帰的にTable関数を呼び出すように修正してみます。

error_reporting(E_ALL);
$arr = ['apple','google','microsoft','os'=>['mac','android','windows']];
);

//  ...
function Table($arr){
  $table = '<table style="border:1px solid black; border-collapse: collapse">';
  foreach( $arr as $i => $value ){
    if( gettype($value) == 'array' ){
      $value = Table($value); // ⬅️再帰呼び出し‼️
    }
    $table .= '<tr>';
    $table .= "<th>{$i}</th><td>{$value}</td>";
    $table .= '</tr>';
  }
  $table .= '</table>';
  return $table;
}

上記は、変数の型が配列だったら、Table関数内で、Table関数を呼び出しています。
これが再帰処理が本領を発揮する場面です!
そして、これは自動的に多次元配列もサポートしています。ご自身で多次元配列の実行できることを試してみて下さい!

型を表示する

このTable関数を実際にデバッグで使うと、少し不自由な点があります。それは、falsenullが表示されず、true1 と表示されます。
以下のような配列をTable関数で実行してみて下さい。

$arr = [0, 1, '0', '1', true, false, null];
echo Table($arr);

これは何が問題かというと、プログラムによっては 1'1'false0 の違いがバグの原因になることがあるので、きちんと表示を分けれた方がデバッグの役に立ちます。

これらの問題も解決してみたいと思います。

error_reporting(E_ALL);
$arr = [0, 1, '0', '1', true, false, null];
echo Table($arr);

//  ...
function Table($arr){
  $table = '<table style="border:1px solid black; border-collapse: collapse">';
  foreach( $arr as $i => $value ){
    switch( gettype($value) ){
      case 'NULL':
        $value = 'NULL';
        break;
      case 'boolean':
        $value = $value ? 'true': 'false';
        break;
      case 'string':
        $value = "'{$value}'";
        break;
      case 'array':
        $value = Table($value); // ⬅️再帰呼び出し‼️
        break;
    }
    $table .= '<tr>';
    $table .= "<th>{$i}</th><td>{$value}</td>";
    $table .= '</tr>';
  }
  $table .= '</table>';
  return $table;
}

後書き

プログラムが得意な分野は、繰り返し処理です。
定型的な処理を高速に繰り返す分野で、コンピューターは力を発揮します。
再帰処理は、コンピューターのコンピューターらしい使い方の一つです。

デバッグ専用に修正しました

デバッグ専用に修正しました。デバッグには、こちらの方が使いやすいと思います。
https://zenn.dev/phpbeginners/articles/6a5f15b2b601e0

Discussion