[PHP] Embed SAPIでCからPHPを呼び出してみる その3

2018年6月11日月曜日

PHP SAPI

[PHP] Embed SAPIでCからPHPを呼び出してみる その2では、zend_eval_stringlを使って、文字列をPHPスクリプトとして解釈、実行してみた。
今度は定義済みのPHP関数をCから呼び出してみよう。

※今回も同様に、Linux上で、PHP 7.1.1を使った例。

全体

CからPHPの定義済み関数を呼び出すにはcall_user_functionを使う。

call_func.c
#include <string.h>
#include <sapi/embed/php_embed.h>

int main(int argc, char *argv[]) {
    PHP_EMBED_START_BLOCK(argc, argv)

    char php_src[] = "function add($x, $y) { return $x + $y; }";
    int stat = zend_eval_stringl(php_src, strlen(php_src), NULL, "phpsrc");
    printf("%d\n", stat);

    zval func = {{ 0 }};
    ZVAL_STRING(&func, "add");
    zval args[2];
    ZVAL_LONG(&args[0], 2L);
    ZVAL_LONG(&args[1], 3L);
    zval ret = {{ 0 }};

    call_user_function(EG(function_table), NULL, &func, &ret, 2, args);
    printf("%d\n", Z_TYPE(ret));
    printf("%d\n", Z_TYPE(ret) == IS_LONG);
    printf("%ld\n", Z_LVAL(ret));

    PHP_EMBED_END_BLOCK()

    return 0;
}

関数定義

7-9行目で、zend_eval_stringlを使って、PHPのユーザ定義関数を定義している。
ここはほぼ前回と一緒だけど、今回は最終的な値がないので、第3引数にNULLを渡している。

関数呼び出し

11-16行目で、呼び出す関数の関数名、引数値、戻り値用変数を用意している。
関数名、引数値もすべて、zvalにする必要があるため、ZVAL_STRINGやZVAL_LONGといったマクロを使って、Cの値からPHPの値に変換する。

18行目で、call_user_functionを使って、関数を呼び出す。
この時、関数が登録されているテーブルを渡す必要があるけど、SAPIのグローバルテーブルの場合は"EG(function_table)"を渡せばいい。

19-21行目の戻り値の扱いは前回と同じで、LONG型のzvalから値をCのlongとして取り出している。

ビルド & 実行


$ export PHP_INCLUDE=/path/to/include/php
$ gcc -Wall -I$PHP_INCLUDE -I$PHP_INCLUDE/main -I$PHP_INCLUDE/Zend -I$PHP_INCLUDE/TSRM -I$PHP_INCLUDE/sapi -L/path/to/lib -lphp7 -o call_func call_func.c
$ LD_LIBRARY_PATH=/path/to/lib ./call_func
0
4
1
5