## 基础 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");
    // call C's 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);
    // 打印完整数据结构
    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");
    // print C's 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]");
    // 使用它就像使用常规数组
    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