C コードは php プログラムで使用する必要があり、次の 2 つの状況で使用する必要があります:
1 すでに C コードがあり、それを PHP プログラムで直接使用したいです
2 PHP のパフォーマンスの問題により、一部の関数を実装するには C を使用する必要があります
最初のケースでは、システム コールを使用して既存の C コードを独立したプログラムに書き込むのが最も適切な方法です。パラメーターはコマンド ラインまたは標準入力を通じて渡され、結果は標準出力から読み取られます。次に、少し面倒な方法は、C コードをデーモンとして記述し、PHP プログラムがソケットを使用してデーモンと通信することです。
2 番目のケースに注目してください。システム コール方式を使用することもできますが、多くのプロセスを頻繁に起動すると、当然ながらパフォーマンスが低下することを考慮してください。デーモンを作成する方法は確かに実行可能ですが、はるかに複雑です。
私の簡単なテストでは、同じアルゴリズムが PHP よりも C で書かれた方が 500 倍効率的であることがわかりました。また、PHP 拡張機能を使用すると、90 倍以上改善することもできます (パフォーマンスの低下はパラメーターの受け渡しにあると思います)。
そのため、php 拡張機能が最良の選択となる場合もあります。
ここでは、PHP を再コンパイルせずに C で PHP 拡張機能を記述する方法に焦点を当てます。
まず、PHP ソース コードを見つけます。これは、ターゲット プラットフォームの PHP バージョンとは関係ありません。
ソースコードの ext ディレクトリに ext_skel という名前のスクリプトがあります (Windows プラットフォームでは ext_skel_win32.php を使用します)
このディレクトリで ./ext_skel --extname=hello を実行します (例として hello を使用します)
ディレクトリが生成されます現時点では、ディレクトリ内にいくつかのファイルがあります。config.m4 hello.c php_hello.h
このディレクトリを任意の場所にコピーし、そこに cd して、
phpize
/configure
make
を実行しても何も起こりませんよね?
これは手順を見逃したためです。config.m4 を開いて次の
dnl を見つけます。拡張機能が外部のものを参照している場合は、with:
..
dnl を使用します。それ以外の場合は、enable:
..
を使用します。これは拡張機能を選択するためのものです。で使用する または有効にして、使用しましょう。 with 部分のコメントを解除します。
私と同じように vim エディターを使用している場合は、3 文字の dnl が元々コメントを表していることが簡単にわかるでしょう (これは、vim にはデフォルトでさまざまなファイル形式用の構文カラーリング パッケージが付属しているためです)
config.m4 を変更したら、
phpize
/configure
make
を続けます。このとき、モジュールの下に hello.so および hello.la ファイルが生成されます。 1 つは動的ライブラリで、もう 1 つは静的ライブラリです。
php 拡張機能は準備ができていますが、まだ必要な機能を実現していません。まず、この拡張機能の使用方法について説明します。 ext_skel は呼び出し例を使用して hello.php を生成しましたが、その例では hello.so を PHP の拡張ディレクトリにコピーする必要があります。私たちは独自の関数を実装したいだけであり、PHP のコピーバージョンを作成したくありません。代わりに、次を使用してロードします:
人々が次に懸念しているのは、関数を追加し、パラメーターの転送と戻り値を実装する方法です
関数を追加する手順は次のとおりです:
php_hello.h:
PHP_FUNCTION(confirm_hello_compiled) // 括弧内に関数名を入力します
hello.c
zend_function_entry hello_functions[] = {
PHP_FE(confirm_hello_compiled, NULL) /* ここに行を追加します*/
{NULL, NULL, NULL} /* hello_functions[] の最後の行である必要があります */
};
PHP_FUNCTION(confirm_hello_compiled)
{//ここに関数本体を記述します
}
実装される関数のプロトタイプは実際には同じです。さらに、hello_functions に次のことを示す情報が 1 行追加されます。この機能があります。
つまり、それらはすべて同じ関数プロトタイプを持っていますが、戻り値とパラメーターをどのように区別するのでしょうか?
例を示します:
把这个当成是scanf来理解好了。
类型说明见下表:
Boolean | b |
zend_bool |
Long | l |
long |
Double | d |
double |
String | s |
char*, int |
Resource | r |
zval* |
Array | a |
zval* |
Object | o |
zval* |
zval | z |
zval* |
如果想实现可选参数的话,例如一个字符串,一个浮点,再加一个可选的bool型,可以用"sd|b"来表示。
和scanf有一点不同的是,对于字符串,你要提供两个变量来存储,一个是char *,存字符串的地址,一个int,来存字符串的长度。这样有必要的时候,你可以安全的处理二进制数据。
那么返回值怎么办呢?
使用下面一组宏来表示:
RETURN_STRING
RETURN_LONG
RETURN_DOUBLE
RETURN_BOOL
RETURN_NULL
注意RETURN_STRING有两个参数
当你需要复制一份字符串时使用
RETURN_STRING("Hello World", 1);
否则使用
RETURN_STRING(str, 0);
这里涉及到了模块中内存的分配,当你申请的内存需要php程序中去释放的话,请参照如下表
Traditional | Non-Persistent | Persistent |
---|---|---|
malloc(count) calloc(count, num)
|
emalloc(count) ecalloc(count, num)
|
pemalloc(count, 1) *pecalloc(count, num, 1)
|
strdup(str) strndup(str, len)
|
estrdup(str) estrndup(str, len)
|
pestrdup(str, 1) pemalloc() & memcpy()
|
無料(ポイント) |
efree(ptr) |
pefree(ptr, 1) |
realloc(ptr, newsize) |
errealloc(ptr, newsize) |
perrealloc(ptr, newsize, 1) |
malloc(count * num + extr) **
|
safe_emalloc(カウント、数値、拡張子) |
safe_pemalloc(count, num, extr) |
通常は、「非永続的」にリストされているものを使用します。
基本的にはこれで、php 拡張機能の作成を開始できます。
今のアプリからは文字列操作ができれば十分なので、これくらいしか紹介できません。