## Базовая работа с модулем FFI

Перед погружением в детали API-интерфейса модуля FFI, давайте рассмотрим несколько примеров упрощённой работы API модуля FFI в стандартных задачах.

> Замечание: Для ряда этих примеров потребуется библиотека 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 требуются конкретные соглашения о вызовах, например: `__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)

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open