長い間、PHPの拡張機能の開発経験を共有することを考えていましたが、ずっと忘れていました=)
さて、VS2008でPHPの拡張機能を作成する基本についてhabratopikを見たので、私は最終的にそれを行うことにしました。
このトピックでは基本事項の概要を説明したため、すぐにさらに微妙な点に進みます。
テキスト出力
標準のprintf()関数の代わりにテキストを表示する必要がある場合は、zend_printf()関数を使用します。 HTTPリクエストを処理するために私たちを呼び出したスクリプトが実行されると、zend_printf()を介して表示される情報はクライアントに直接送信されます。 スタンドアロンモードでphpを実行すると、画面にテキストが表示されます。
参照による関数パラメーターの受け渡し
PHP 5.3.0以降では、関数を呼び出すときに引数を参照によって関数に渡すことは推奨されないため、引数は関数宣言で参照渡しとして宣言する必要があります。 PHPで関数を宣言する場合(すべてが単純です)、引数名の前にアンパサンドを置くだけで、たとえば次のようになります。
function ReadData($id,&$data)
拡張機能で関数を宣言すると、すべてが多少複雑になります。
まず、関数の引数を記述する必要があります。
ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args)
ZEND_ARG_INFO(pass_by_ref, name)
...
ZEND_END_ARG_INFO()
マクロオプションZEND_BEGIN_ARG_INFO_EX():
name-この引数のリストを記述する構造の名前。 一意でなければなりません。 たとえば、ReadData()関数の場合、構造体はarginfo_readdataと呼ばれます。
required_num_args-必要な関数引数の数。
pass_rest_by_reference-残りの(オプションの)引数を参照で渡すかどうか(0-いいえ、1-はい)。
return_reference-戻り値が参照によって渡されるかどうか。
ZEND_ARG_INFO()マクロオプション:
pass_by_ref-この引数を参照渡しします。
name-引数の名前。
すべての引数は、関数に渡されるのと同じ順序でリストされます。
同じReadData関数を宣言する例:
ZEND_BEGIN_ARG_INFO_EX(arginfo_readdata,0,0,2)
ZEND_ARG_INFO(0,id)
ZEND_ARG_INFO(1,data)
ZEND_END_ARG_INFO()
その後、関数を宣言するときに、引数記述構造の名前をPHP_FE()マクロの2番目のパラメーターとして指定するだけで十分です。 例:
PHP_FE(readdata,arginfo_readdata)
zvalとは何ですか?
zvalは、PHP変数の表現を含む構造です。 スカラー値(数値、文字列など)とリソースの配列またはハンドルの両方を含めることができます。
拡張関数を引数として受け入れるか、関数から配列を返す場合、このzvalを使用する必要があります。
zvalを取得します
たとえば、連想配列を関数の引数として取得し、そのインデックスから値を取得する必要があります。
これを行うには、zvalへのポインターを宣言します。 zend_parse_parameters関数を呼び出すときに、引数のタイプ「a」を指定します。 宣言されたzvalへのポインタへのポインタを渡します。
すぐにサンプルコード:
PHP_FUNCTION(func)
{
zval *arr;
char buf[128];
unsigned long x,y;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a" , &arr)==FAILURE) {
WRONG_PARAM_COUNT;
}
...
}
* This source code was highlighted with Source Code Highlighter .
配列から値を取得する
前の例の関数を続け、渡された配列からインデックスxとyの値を取得し、その後「x = ...、y = ...」の形式の文字列を作成して出力します。 この例では、これらの値はlong型になりますが、わずかな変更を加えて、他の型も取得できます。
PHP_FUNCTION(func)
{
zval *arr,**val;
char buf[128];
unsigned long x,y;
HashTable *hash;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a" , &arr)==FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_P(arr)!=IS_ARRAY) {
zend_error(E_ERROR, "%s(): Supplied argument is not an array." ,get_active_function_name(TSRLM_C));
RETURN_BOOL(0);
}
hash=Z_ARRVAL_P(arr);
if (zend_hash_find(hash, "x" ,1,( void **)&val)!=SUCCESS) {
zend_error(E_ERROR, "%s(): There is no x index." ,get_active_function_name(TSRLM_C));
RETURN_BOOL(0);
}
if (Z_TYPE_PP(val)!=IS_LONG) {
zend_error(E_ERROR, "%s(): Wrong type of x." ,get_active_function_name(TSRLM_C));
RETURN_BOOL(0);
}
x=Z_LVAL_PP(val);
if (zend_hash_find(hash, "y" ,1,( void **)&val)!=SUCCESS) {
zend_error(E_ERROR, "%s(): There is no y index." ,get_active_function_name(TSRLM_C));
RETURN_BOOL(0);
}
if (Z_TYPE_PP(val)!=IS_LONG) {
zend_error(E_ERROR, "%s(): Wrong type of y." ,get_active_function_name(TSRLM_C));
RETURN_BOOL(0);
}
y=Z_LVAL_PP(val);
zend_printf( "x = %u, y = %u\n" ,x,y);
}
* This source code was highlighted with Source Code Highlighter .
この例では、Zendマクロが広く使用されています。
Z_TYPE _ *()は、渡されたzvalに含まれるタイプを返します。 ご想像のとおり、値の形式はIS_typeです。 たとえば、IS_ARRAYまたはIS_STRING。
Z_ARRVAL _ *()は、PHP配列の内部表現であるHashTable構造体へのポインターを返します。
Z_LVAL _ *()は、渡されたzvalに含まれる数値を返します。
*-ポインタをzvalに渡すか、ポインタをzvalに渡すかによって、PまたはPPになります。
zend_hash_find(zval *)関数は、渡されたHashTableで指定されたインデックスを検索します。
残りは明確にする必要があります。
指定されたコードは明らかにobviouslyくて最適ではありません。ここでは例としてのみ=)
おわりに
このトピックがhabrasocietyにどれほど面白いかはわかりません。そのため、今のところはこれ以上ペイントしません。
トピックが興味深いことが判明した場合、拡張機能で関数を作成する他の微妙な点についてお話しできることを嬉しく思います。
私はトピックとスタイルに関するコメントを聞いてうれしいです、これは私の最初のhabratopik =)すべて同じです