Простые примеры использования FFI
Перед погружением в детали FFI API, давайте рассмотрим несколько примеров упрощенного использования FFI API в стандартных задачах.
Замечание:
Для некоторых из этих примеров понадобится библиотека libc.so.6. Они не будут работать в системах, где её нет.
Пример #1 Вызов функции из общей библиотеки
<?php
// создаем объект FFI, загружаем libc и экспортируем функцию printf()
$ffi = FFI::cdef(
"int printf(const char *format, ...);", // это стандартная декларация C
"libc.so.6");
// вызываем printf()
$ffi->printf("Привет, %s!\n", "мир");
?>
Результат выполнения данного примера:
Привет, мир!
Замечание:
Обратите внимание, что для некоторых функций C требуются определенные соглашения о вызовах, например6
__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");
// вызываем gettimeofday()
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz)));
// получаем доступ к полю структуры данных C
var_dump($tv->tv_sec);
// печатаем всю структуру данных
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");
// печатаем 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
// создаем структуру данных
$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
<?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)