PHPのFFI(外部関数インターフェイス)拡張により、PHPでC言語関数とデータ構造を直接呼び出すことができます。これは、パフォーマンスに敏感または基礎となるインタラクションシナリオの処理に非常に役立ちます。しかし、それを詳細に使用すると、 FFI :: cdef()で構造体を宣言するときに構造体を書くのを忘れた場合はどうなりますか?
単純なC構造があるとします:
typedef struct {
int x;
int y;
} Point;
PHPのFFI :: CDEF()宣言を使用します。
$ffi = FFI::cdef("
typedef struct {
int x;
int y;
} Point;
");
次に、次のように使用できます。
$point = $ffi->new("Point");
$point->x = 10;
$point->y = 20;
echo "Point: ({$point->x}, {$point->y})\n";
すべてが正常に実行されています。しかし、問題は次のとおりです。構造を書くのを忘れた場合はどうなりますか?
C言語では、 struct PointとPointは2つの異なる名前空間です。 Typedefを使用しない限り、 Pointは有効なタイプ名ではありません。 PHPのFFI :: cdef()では、状況はわずかに異なります。その解析ルールはCコンパイラのルールとはわずかに異なり、断層許容度は低くなっています。
たとえば、次のような声明を書きました。
$ffi = FFI::cdef("
typedef struct Point {
int x;
int y;
} Point;
");
$pt = $ffi->new("Point");
このコードは大丈夫です。しかし、あなたが不注意にtypedef部分を見逃している場合、例えば:
$ffi = FFI::cdef("
struct Point {
int x;
int y;
};
");
$pt = $ffi->new("Point"); // エラーが発生しました
ここでは、$ ffi-> new( "point")が例外をスローし、型「ポイント」が見つからないように促します。なぜなら、この時点で「ポイント」は構造ポイントであり、別のタイプのエイリアスではないからです。
正しい呼び出しは次のとおりです。
$pt = $ffi->new("struct Point");
これは、多くの人々が該当する落とし穴です。彼らは構造名「ポイント」を定義したと考えていますが、実際には「構造ポイント」のみを定義します。 typedefを実行しない場合、ポイントを直接使用することはできません。
次のようなエラーが表示された場合:
FFI\Exception: undefined C type 'Point'
次に、最初にcdef()でそれを宣言する方法を確認する必要があります。 typedefなしでstruct Pointを書いただけですか?その場合、 struct Pointのみを参照することができます。
デバッグ手法は、CDEF()宣言を印刷して、構造にtypedefがあるかどうかを確認することです。
echo $ffi->cdef;
この方法は常に機能するとは限りませんが(特にPHPの一部のバージョンでは)、タイプが正しく登録されていることを確認するのに役立ちます。
混乱を避けるために、すべての構造宣言にTypedefを持ち込むことをお勧めします。例えば:
typedef struct {
int x;
int y;
} Point;
このようにして、PHPで$ ffi-> new( "Point")を喜んで書くことができ、 structプレフィックスを追加するかどうかを心配する必要がなくなります。
別の構造をネストする構造を定義するとします。
typedef struct {
int x;
int y;
} Point;
typedef struct {
Point start;
Point end;
} Line;
ffi :: phpのcdef()は次のように書く必要があります:
$ffi = FFI::cdef("
typedef struct {
int x;
int y;
} Point;
typedef struct {
Point start;
Point end;
} Line;
");
次に、次のように使用できます。
$line = $ffi->new("Line");
$line->start->x = 1;
$line->start->y = 2;
$line->end->x = 10;
$line->end->y = 20;
echo "Start: ({$line->start->x}, {$line->start->y})\n";
echo "End: ({$line->end->x}, {$line->end->y})\n";
Pointがtypedefを持っていないなど、宣言でtypedefを逃した場合、行の定義はポイントタイプが見つからないためエラーを報告します。
PHP FFIを使用してCの構造を呼び出すときは、次のポイントに注意してください。
構造がtypedefでない場合、タイプ名はstructでプレフィックスする必要があります
すべての構造物がtypedef宣言を使用して混乱の命名を避けることをお勧めします
デバッグ時に、未定義のタイプエラーに遭遇しました。まず、CDEFの宣言が一貫しているかどうかを確認します。
これらの仕様により、多くの不可解なタイプエラーを減らすことができ、PHPでCインターフェイスをプレイするときに落とし穴を減らし、髪を失うことができます。
PHP FFIの詳細については、 https://gitbox.net/docs/php-ffi-examplesを参照してください。