FFI API の詳細に深く立ち入る前に、よくあるタスクに対する FFI API の使い方が どれほど簡単かを示す例をいくつか見てみましょう。
注意: これらの例の中には、libc.so.6 を必要とするものがあります。 それらは、このライブラリが利用できないシステムでは動きません。
例1 共有ライブラリの関数を呼ぶ
<?php
// FFI オブジェクトを作成し、libc を読み込んで printf() 関数をエクスポートする
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // ここは通常の C の宣言
"libc.so.6");
// C の printf() を呼ぶ
$ffi->printf("Hello %s!\n", "world");
?>上の例の出力は以下となります。
Hello world!
注意: C の関数のうちのいくつかは、特定の呼び出し規約 (例:
__fastcall、__stdcall、,__vectorcallなど) を必要とすることに注意してください。
例2 関数を呼び出し、構造体を引数経由で返す
<?php
// gettimeofday() のバインディングを作成する
$ffi = FFI::cdef("
typedef unsigned int time_t;
typedef unsigned int suseconds_t;
struct timeval {
time_t tv_sec;
suseconds_t tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
int gettimeofday(struct timeval *tv, struct timezone *tz);
", "libc.so.6");
// C のデータ構造を作成する
$tv = $ffi->new("struct timeval");
$tz = $ffi->new("struct timezone");
// C の gettimeofday() を呼ぶ
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz)));
// C のデータ構造のフィールドにアクセスする
var_dump($tv->tv_sec);
// C のデータ構造全体を出力する
var_dump($tz);
?>上の例の出力は、 たとえば以下のようになります。
int(0)
int(1555946835)
object(FFI\CData:struct timezone)#3 (2) {
["tz_minuteswest"]=>
int(0)
["tz_dsttime"]=>
int(0)
}
例3 既存の C の変数にアクセスする
<?php
// FFI オブジェクトを作成し、libc を読み込んで errno 変数をエクスポートする
$ffi = FFI::cdef(
"int errno;", // ここは通常の C の宣言
"libc.so.6");
// C の errno を出力する
var_dump($ffi->errno);
?>上の例の出力は以下となります。
int(0)
例4 C の変数を作成して書き換える
<?php
// 新しい C の int 変数を作成する
$x = FFI::new("int");
var_dump($x->cdata);
// 単純な代入
$x->cdata = 5;
var_dump($x->cdata);
// 複合代入
$x->cdata += 2;
var_dump($x->cdata);
?>上の例の出力は以下となります。
int(0) int(5) int(7)
例5 C の配列を扱う
<?php
// C のデータ構造を作成する
$a = FFI::new("long[1024]");
// 通常の PHP の配列を扱うのと同じように扱う
for ($i = 0; $i < count($a); $i++) {
$a[$i] = $i;
}
var_dump($a[25]);
$sum = 0;
foreach ($a as $n) {
$sum += $n;
}
var_dump($sum);
var_dump(count($a));
var_dump(FFI::sizeof($a));
?>上の例の出力は以下となります。
int(25) int(523776) int(1024) int(8192)
例6 C の enum を扱う
<?php
$a = FFI::cdef('typedef enum _zend_ffi_symbol_kind {
ZEND_FFI_SYM_TYPE,
ZEND_FFI_SYM_CONST = 2,
ZEND_FFI_SYM_VAR,
ZEND_FFI_SYM_FUNC
} zend_ffi_symbol_kind;
');
var_dump($a->ZEND_FFI_SYM_TYPE);
var_dump($a->ZEND_FFI_SYM_CONST);
var_dump($a->ZEND_FFI_SYM_VAR);
?>上の例の出力は以下となります。
int(0) int(2) int(3)