こんにちは、高木です。
前回まではPHPで構造体を自動生成してきました。今回は構造体ではなく列挙体を作ってみることにします。それだけでは面白みがないので、列挙定数を与えると、その名前の文字列に変換する関数も自動生成してみましょう。
まずは列挙体を自動生成するPHPのコードからです。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?php $direction_type = [ 'upward', 'rightward', 'downward', 'leftward', 'none' => -1, ]; function make_enum(string $name, array $type): string { $r = "typedef enum {\n"; foreach ($type as $key => $value) { $r .= "\t"; if (is_int($key)) { $r .= "$value,\n"; } else { $r .= "$key = $value,\n"; } } $r .= "} $name;\n"; return $r; } ?> |
構造体のときと基本的には変わりません。注目すべき点は、列挙定数の定義時に定数値を指定する場合としない場合がある点です。
今回作るdirection_t型の場合、noneだけが定数値-1を指定しており、それ以外は定数値を指定していません。
PHPの配列は、要素にキー無しの値だけを指定すると、連番を表す整数値がキーになります。これを利用して、キーが整数であれば定数値の指定無し、それ以外は定数値の指定ありと判断しています。
このmake_enum関数を使って列挙体を生成するには次のようにします。
0 1 2 3 4 |
<?php echo make_enum('direction_t', $direction_type); ?> |
さて、いよいよ列挙定数から文字列を自動生成するPHPのコードを書いていきます。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
<?php function make_enum_to_string(string $name, array $type) { // caseラベルの並びを生成する。 $case_table = ''; foreach ($type as $key => $value) { if (is_int($key)) { $enumerator = $value; } else { $enumerator = $key; } $case_table .= <<< EOT case $enumerator: s = "$enumerator"; break; EOT; } // 関数のひな形にcaseラベルの並びを埋め込んで返す。 return <<<EOT const char *{$name}_to_string($name value) { const char *s = NULL; switch (value) { $case_table } return s; } EOT; } ?> |
今度はちょっと複雑ですね。関数やcaseラベルからbreak文までは決まり切った内容なので、ヒアドキュメントを使ってひな形を作っています。あとは、make_enum関数と同様、列挙定数に定数値を指定するかどうかで処理を変えています。
上記で作ったmake_enum_to_string関数の使い方は簡単です。
0 1 2 3 4 |
<?php echo make_enum_to_string('direction_t', $direction_type); ?> |
このように書けば、direction_t_to_string関数を自動生成することができます。