こんにちは、高木です。
前回は、PHPでC言語の関数宣言をさせると何が嬉しいのかという問いかけをして終わりました。今回は、その「なぜ嬉しいのか」について書くことにします。
C言語で実装した関数は、C++をはじめ、さまざまな言語から呼び出すことができます。具体例を挙げると、C言語で実装したDLLはC#などの.NET言語からDllImportして呼び出すことができますね。今回は、C言語の関数宣言を生成させるために使ったPHPのデータを利用して、C#のDllImport宣言を生成してみることにします。
前回はfgets関数の宣言を生成させましたが、今回は話を簡単にするために、2つの整数値を受け取って整数値を返すfunc関数を考えてみることにします。
| 0 1 2 | int func(int a, long long b); | 
上のような関数を想定しています。前回作ったmake_signature関数に与えるデータは次のようになります。
| 0 1 2 3 4 5 6 7 8 9 10 | <?php $func_type = [   [     'a' => 'int',     'b' => 'long long',   ],   'int', ]; ?> | 
次に、C#のDllImport宣言を生成するmake_csharp_dllimport関数を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 | $csharp_type_map = [   'int' => 'int',   'long long' => 'long', ]; function make_csharp_dllimport(string $dllname, string $name, $type): string {   global $csharp_type_map;   // 仮引数並びの生成   $parameter_list = '';   foreach ($type[0] as $key => $value)   {     if (strlen($parameter_list) !== 0)       $parameter_list .= ', ';     if (is_array($value))     {       $paremeter_list .= $csharp_type_map[$value[0]] . " {$key}[{$value[1]}]";     }     else     {       $parameter_list .= $csharp_type_map[$value] . " $key";     }   }   if (strlen($parameter_list) === 0)     $parameter_list = 'void';   // 結果を合成する。   return <<<EOT   [DllImport("$dllname")]   private static extern {$type[1]} $name($parameter_list) EOT; } ?> | 
配列$csharp_type_map は、C言語の型とC#の型との対応表です。今回は必要最小限の対応しか定義していませんが、実際にはもっと大きな表になります。
ここまでできたら、次のように呼び出すことでDllImport宣言を生成することができます。
| 0 1 2 3 4 | <?php echo make_csharp_dllimport('func.dll', 'func', $func_type); ?>; | 
make_signature関数に合わせて、宣言末尾のセミコロンは自分で自分で書く仕様にしています。生成されたDllImport宣言は次のようになります。
| 0 1 2 3 |   [DllImport("func.dll")]   private static extern int func(int a, long b); | 
実際のDllImportでは、CallingConventionやCharSetなどいくつかのオプションを付けてあげないといけないことが多いので、そうした対応も必要になると思います。今回はあくまでも説明用に最小限の内容にとどめています。
最初にも書いたように、C言語で実装した関数はさまざまなプログラミング言語から呼び出すことができます。今回はC#しか扱いませんでしたが、同じようにすればVisual Basic.NET用のDllImport宣言を作れるでしょうし、.NET以外の、たとえばRustなどから呼び出すための宣言を生成することもできます。最近のスクリプト言語にはFFI(foreign function interface)の機能が備わっていることも多いので、そのための記述を生成することもできるでしょう。
こんな感じで、PHPでC言語の前処理を行うだけにとどまらず、いろいろ応用ができるようになります。






![[迷信] 'A'~'Z'の値は連続している](https://www.kijineko.co.jp/wp-content/uploads/2021/05/2120715_s.jpg)