久久精品水蜜桃av综合天堂,久久精品丝袜高跟鞋,精品国产肉丝袜久久,国产一区二区三区色噜噜,黑人video粗暴亚裔

PHP FFI

2024-02-02 199

FFI允許在純 PHP 中加載共享庫(.DLL 或 .so)、調(diào)用 C 函數(shù)、訪問 C 數(shù)據(jù)結(jié)構(gòu),而無需深入了解 Zend 擴(kuò)展 API,也無需學(xué)習(xí)第三方“中間”語言。該擴(kuò)展的公共 API 由 FFI 類實(shí)現(xiàn),其中包含幾個靜態(tài)方法和對象重載方法,用于執(zhí)行與 C 數(shù)據(jù)的實(shí)際交互。

簡單來說,這個擴(kuò)展使得 PHP 開發(fā)者可以使用 C 語言編寫的庫,并在 PHP 中輕松地調(diào)用其中的函數(shù)和訪問 C 語言中定義的數(shù)據(jù)結(jié)構(gòu),無需編寫 C 擴(kuò)展或了解底層的 C 函數(shù)調(diào)用方式。這個擴(kuò)展的核心是 FFI 類,它提供了一系列靜態(tài)方法和對象重載方法,用于在 PHP 中調(diào)用 C 函數(shù)和訪問 C 數(shù)據(jù)結(jié)構(gòu)。

一、基礎(chǔ)FFI用法

在深入了解 FFI API 細(xì)節(jié)之前,先看幾個示例,展示 FFI API 在常規(guī)任務(wù)中的簡單使用。

注意:其中一些示例需要 libc.so.6,因此在沒有該庫的系統(tǒng)上無法運(yùn)行。

從共享庫中調(diào)用函數(shù):

<?php
// 創(chuàng)建 FFI 對象,加載 libc 和輸出函數(shù) 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 函數(shù)需要特定的調(diào)用規(guī)則,例如 __fastcall、__stdcall 或 __vectorcall。

調(diào)用函數(shù),通過參數(shù)返回結(jié)構(gòu)體:

<?php
// 創(chuàng)建 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");
// 創(chuàng)建 C 數(shù)據(jù)結(jié)構(gòu)
$tv = $ffi->new("struct timeval");
$tz = $ffi->new("struct timezone");
// 調(diào)用 C 的 gettimeofday()
var_dump($ffi->gettimeofday(FFI::addr($tv), FFI::addr($tz)));
// 訪問 C 數(shù)據(jù)結(jié)構(gòu)的字段
var_dump($tv->tv_sec);
// 打印完整數(shù)據(jù)結(jié)構(gòu)
var_dump($tz);
?>

以上示例的輸出類似于:

int(0)
int(1555946835)
object(FFI\CData:struct timezone)#3 (2) {
["tz_minuteswest"]=>
int(0)
["tz_dsttime"]=>
int(0)
}

訪問已存在的 C 變量:

<?php
// 創(chuàng)建 FFI 對象,加載 libc 和輸出 errno 變量
$ffi = FFI::cdef(
"int errno;", // 這是普遍的 C 聲明
"libc.so.6");
// print C's errno
var_dump($ffi->errno);
?>

以上示例會輸出:

int(0)

創(chuàng)建和修改 C 變量:

<?php
// 創(chuàng)建新的 C int 變量
$x = FFI::new("int");
var_dump($x->cdata);
// 簡單賦值
$x->cdata = 5;
var_dump($x->cdata);
// 復(fù)合賦值
$x->cdata += 2;
var_dump($x->cdata);
?>

以上示例會輸出:

int(0)
int(5)
int(7)

使用 C 數(shù)組:

<?php
// 創(chuàng)建 C 數(shù)據(jù)結(jié)構(gòu)
$a = FFI::new("long[1024]");
// 使用它就像使用常規(guī)數(shù)組
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)

使用 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)

二、PHP回調(diào)

可以將 PHP 閉包分配給函數(shù)指針類型的原生變量,或?qū)⑵渥鳛楹瘮?shù)參數(shù)傳遞。

<?php
$zend = FFI::cdef("
typedef int (*zend_write_func_t)(const char *str, size_t str_length);
extern zend_write_func_t zend_write;
");
echo "Hello World 1!\n";
$orig_zend_write = clone $zend->zend_write;
$zend->zend_write = function($str, $len) {
global $orig_zend_write;
$orig_zend_write("{\n\t", 3);
$ret = $orig_zend_write($str, $len);
$orig_zend_write("}\n", 2);
return $ret;
};
echo "Hello World 2!\n";
$zend->zend_write = $orig_zend_write;
echo "Hello World 3!\n";
?>

以上示例會輸出:

Hello World 1!
{
Hello World 2!
}
Hello World 3!

三、完整PHP/FFI/preloading

以下是完整的PHP/FFI/preloading示例:

1、php.ini

ffi.enable=preload
opcache.preload=preload.php

2、preload.php

<?php
FFI::load(__DIR__ . "/dummy.h");
opcache_compile_file(__DIR__ . "/dummy.php");
?>

3、dummy.h

#define FFI_SCOPE "DUMMY"
#define FFI_LIB "libc.so.6"
int printf(const char *format, ...);

4、dummy.php

<?php
final class Dummy {
private static $ffi = null;
function __construct() {
if (is_null(self::$ffi)) {
self::$ffi = FFI::scope("DUMMY");
}
}
function printf($format, ...$args) {
return (int)self::$ffi->printf($format, ...$args);
}
}
?>

5、test.php

<?php
$d = new Dummy();
$d->printf("Hello %s!\n", "world");
?>

四、C代碼和數(shù)據(jù)主接口

通過工廠方法 FFI::cdef()、FFI::load() 或 FFI::scope() 創(chuàng)建該類的對象。定義的 C 變量作為有效的 FFI 實(shí)例屬性,定義的 C 函數(shù)作為有效的 FFI 實(shí)例方法。聲明的 C 類型可以用于 FFI::new() 和 FFI::type() 創(chuàng)建新的 C 數(shù)據(jù)結(jié)構(gòu)。

FFI 定義解析和共享庫加載可能需要較長時間。在 Web 環(huán)境中,每個 HTTP 請求都進(jìn)行這些操作是沒有意義的。然而,在 PHP 啟動時預(yù)加載 FFI 定義和庫,并在需要時實(shí)例化 FFI 對象是可能的。header 文件可以使用特殊的 FFI_SCOPE 定義進(jìn)行擴(kuò)展(例如 #define FFI_SCOPE “foo”),然后在預(yù)加載期間由 FFI::load() 加載。這將創(chuàng)建持久綁定,將通過 FFI::scope() 在所有后續(xù)請求中可用。

類摘要:

final class FFI {
/* 常量 */
public const int __BIGGEST_ALIGNMENT__;
/* 方法 */
public static addr(FFI\CData &$ptr): FFI\CData
public static alignof(FFI\CData|FFI\CType &$ptr): int
public static arrayType(FFI\CType $type, array $dimensions): FFI\CType
public static cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CData
public cast(FFI\CType|string $type, FFI\CData|int|float|bool|null &$ptr): ?FFI\CData
public static cdef(string $code = "", ?string $lib = null): FFI
public static free(FFI\CData &$ptr): void
public static isNull(FFI\CData &$ptr): bool
public static load(string $filename): ?FFI
public static memcmp(string|FFI\CData &$ptr1, string|FFI\CData &$ptr2, int $size): int
public static memcpy(FFI\CData &$to, FFI\CData|string &$from, int $size): void
public static memset(FFI\CData &$ptr, int $value, int $size): void
public static new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData
public new(FFI\CType|string $type, bool $owned = true, bool $persistent = false): ?FFI\CData
public static scope(string $name): FFI
public static sizeof(FFI\CData|FFI\CType &$ptr): int
public static string(FFI\CData &$ptr, ?int $size = null): string
public static type(string $type): ?FFI\CType
public type(string $type): ?FFI\CType
public static typeof(FFI\CData &$ptr): FFI\CType
}

五、C Data Handles

FFI\CData 對象可以像普通 PHP 數(shù)據(jù)一樣以多種方式使用:

1、標(biāo)量類型的 C 數(shù)據(jù)可以通過 $cdata 屬性讀取和分配,例如:$x = FFI::new(‘int’);$x->cdata = 42。

2、C 結(jié)構(gòu)和聯(lián)合字段可作為常規(guī) PHP 對象屬性訪問,例如:$cdata->field。

3、C 數(shù)組元素可以像普通 PHP 數(shù)組元素一樣訪問,例如:$cdata[$offset]。

4、可以使用 foreach 語句遍歷 C 數(shù)組。

5、C 數(shù)組可用作 count() 的參數(shù)。

6、C 指針可以作為數(shù)組被取消引用,例如 $cdata[0]。

7、C 指針可以使用常規(guī)比較運(yùn)算符(<, <=, ==, !=, >=, >)進(jìn)行比較。

8、C 指針可以使用常規(guī)的 +/-/ ++/– 操作進(jìn)行遞增和遞減,例如:$cdata += 5。

9、C 指針可以通過常規(guī)的 – 運(yùn)算從另一個指針減去。

10、指向函數(shù)的 C 指針可以作為常規(guī)的 PHP 閉包調(diào)用,例如:$cdata()。

11、可以使用克隆運(yùn)算符復(fù)制任何 C 數(shù)據(jù),例如:$cdata2 = clone $cdata。

12、任何 C 數(shù)據(jù)都可以使用 var_dump()、print_r() 等可視化。

六、C Type Handles

1、類摘要

final class FFI\CType {
/* 常量 */
public const int TYPE_VOID;
public const int TYPE_FLOAT;
public const int TYPE_DOUBLE;
public const int TYPE_LONGDOUBLE;
public const int TYPE_UINT8;
public const int TYPE_SINT8;
public const int TYPE_UINT16;
public const int TYPE_SINT16;
public const int TYPE_UINT32;
public const int TYPE_SINT32;
public const int TYPE_UINT64;
public const int TYPE_SINT64;
public const int TYPE_ENUM;
public const int TYPE_BOOL;
public const int TYPE_CHAR;
public const int TYPE_POINTER;
public const int TYPE_FUNC;
public const int TYPE_ARRAY;
public const int TYPE_STRUCT;
public const int ATTR_CONST;
public const int ATTR_INCOMPLETE_TAG;
public const int ATTR_VARIADIC;
public const int ATTR_INCOMPLETE_ARRAY;
public const int ATTR_VLA;
public const int ATTR_UNION;
public const int ATTR_PACKED;
public const int ATTR_MS_STRUCT;
public const int ATTR_GCC_STRUCT;
public const int ABI_DEFAULT;
public const int ABI_CDECL;
public const int ABI_FASTCALL;
public const int ABI_THISCALL;
public const int ABI_STDCALL;
public const int ABI_PASCAL;
public const int ABI_REGISTER;
public const int ABI_MS;
public const int ABI_SYSV;
public const int ABI_VECTORCALL;
/* 方法 */
public getAlignment(): int
public getArrayElementType(): FFI\CType
public getArrayLength(): int
public getAttributes(): int
public getEnumKind(): int
public getFuncABI(): int
public getFuncParameterCount(): int
public getFuncParameterType(int $index): FFI\CType
public getFuncReturnType(): FFI\CType
public getKind(): int
public getName(): string
public getPointerType(): FFI\CType
public getSize(): int
public getStructFieldNames(): array
public getStructFieldOffset(string $name): int
public getStructFieldType(string $name): FFI\CType
}

2、預(yù)定義常量

  • FFI\CType::TYPE_VOID
  • FFI\CType::TYPE_FLOAT
  • FFI\CType::TYPE_DOUBLE
  • FFI\CType::TYPE_LONGDOUBLE
  • FFI\CType::TYPE_UINT8
  • FFI\CType::TYPE_SINT8
  • FFI\CType::TYPE_UINT16
  • FFI\CType::TYPE_SINT16
  • FFI\CType::TYPE_UINT32
  • FFI\CType::TYPE_SINT32
  • FFI\CType::TYPE_UINT64
  • FFI\CType::TYPE_SINT64
  • FFI\CType::TYPE_ENUM
  • FFI\CType::TYPE_BOOL
  • FFI\CType::TYPE_CHAR
  • FFI\CType::TYPE_POINTER
  • FFI\CType::TYPE_FUNC
  • FFI\CType::TYPE_ARRAY
  • FFI\CType::TYPE_STRUCT
  • FFI\CType::ATTR_CONST
  • FFI\CType::ATTR_INCOMPLETE_TAG
  • FFI\CType::ATTR_VARIADIC
  • FFI\CType::ATTR_INCOMPLETE_ARRAY
  • FFI\CType::ATTR_VLA
  • FFI\CType::ATTR_UNION
  • FFI\CType::ATTR_PACKED
  • FFI\CType::ATTR_MS_STRUCT
  • FFI\CType::ATTR_GCC_STRUCT
  • FFI\CType::ABI_DEFAULT
  • FFI\CType::ABI_CDECL
  • FFI\CType::ABI_FASTCALL
  • FFI\CType::ABI_THISCALL
  • FFI\CType::ABI_STDCALL
  • FFI\CType::ABI_PASCAL
  • FFI\CType::ABI_REGISTER
  • FFI\CType::ABI_MS
  • FFI\CType::ABI_SYSV
  • FFI\CType::ABI_VECTORCALL

七、FFI Exceptions

類摘要:

class FFI\Exception extends Error {
/* 繼承的屬性 */
protected string $message = "";
private string $string = "";
protected int $code;
protected string $file = "";
protected int $line;
private array $trace = [];
private ?Throwable $previous = null;
/* 繼承的方法 */
public Error::__construct(string $message = "", int $code = 0, ?Throwable $previous = null)
final public Error::getMessage(): string
final public Error::getPrevious(): ?Throwable
final public Error::getCode(): int
final public Error::getFile(): string
final public Error::getLine(): int
final public Error::getTrace(): array
final public Error::getTraceAsString(): string
public Error::__toString(): string
private Error::__clone(): void
}

八、FFI Parser Exceptions

類摘要:

final class FFI\ParserException extends FFI\Exception {
/* 繼承的屬性 */
protected string $message = "";
private string $string = "";
protected int $code;
protected string $file = "";
protected int $line;
private array $trace = [];
private ?Throwable $previous = null;
/* 繼承的方法 */
public Error::__construct(string $message = "", int $code = 0, ?Throwable $previous = null)
final public Error::getMessage(): string
final public Error::getPrevious(): ?Throwable
final public Error::getCode(): int
final public Error::getFile(): string
final public Error::getLine(): int
final public Error::getTrace(): array
final public Error::getTraceAsString(): string
public Error::__toString(): string
private Error::__clone(): void
}
  • 廣告合作

  • QQ群號:4114653

溫馨提示:
1、本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享網(wǎng)絡(luò)內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。郵箱:2942802716#qq.com(#改為@)。 2、本站原創(chuàng)內(nèi)容未經(jīng)允許不得轉(zhuǎn)裁,轉(zhuǎn)載請注明出處“站長百科”和原文地址。
PHP FFI
上一篇: PHP Componere
PHP FFI
下一篇: PHP OPcache