プログラミング・テクニック:再帰処理(再帰呼び出し)
再帰処理とは
ある関数内で、その関数を呼び出すことです。
この文だけだと意味が分かりませんが、実例を見ればすぐに分かると思います。
// 関数を定義
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関数を実際にデバッグで使うと、少し不自由な点があります。それは、false
やnull
が表示されず、true
は 1
と表示されます。
以下のような配列をTable関数で実行してみて下さい。
$arr = [0, 1, '0', '1', true, false, null];
echo Table($arr);
これは何が問題かというと、プログラムによっては 1
と '1'
、false
と 0
の違いがバグの原因になることがあるので、きちんと表示を分けれた方がデバッグの役に立ちます。
これらの問題も解決してみたいと思います。
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;
}
後書き
プログラムが得意な分野は、繰り返し処理です。
定型的な処理を高速に繰り返す分野で、コンピューターは力を発揮します。
再帰処理は、コンピューターのコンピューターらしい使い方の一つです。
デバッグ専用に修正しました
デバッグ専用に修正しました。デバッグには、こちらの方が使いやすいと思います。
Discussion