関数のパラメータ
関数の呼び出し元によって渡されたパラメータを取得する最も簡単な方法は、zend_parse_parameters() 関数を使用することです。カーネル内のマクロを使用して、zend_parse_parameters() 関数の最初のいくつかのパラメータを ZEND_NUM_ARGS() TSRMLS_CC の形式で直接生成できます。2 つの間にはスペースがありますが、コンマはありません。名前からわかるように、ZEND_NUM_ARGS() はパラメータの数を表します。 zend_parse_parameters() 関数に渡す必要がある次のパラメータは、printf の最初のパラメータと同様に、フォーマットに使用される文字列です。最も一般的に使用される記号のいくつかを以下に示します。
type_spec はフォーマット文字列で、一般的な意味は次のとおりです:
Parameter は型を表します
b ブール型
l Integer 整数型
d 浮動小数点浮動小数点型
s String 文字列
r リソース リソース
a Array 配列
o オブジェクト インスタンスオブジェクト
O 指定された型のオブジェクト インスタンス 特定の型のオブジェクト
z 非指定 zval 任意の型 ~
Z zval** 型
f 関数名やメソッド名を表す PHP5.1 ではそのようなものはないようです。 .. .. .
この関数は、printf() 関数と同様に、フォーマット文字列のフォーマットに 1 対 1 で対応します。一部の基本的なデータ型は、C 言語の型に直接マッピングされます。
ZEND_FUNCTION(sample_getlong) {
long foo;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"l", &foo) == FAILURE)
{ RETURN_NULL()
}
php_printf("パラメータは: %ldn", foo);
RETURN_TRUE;
}
一般的に、int と long の 2 つのデータ型のデータは同じであることが多いですが、例外もあります。したがって、特に 64 ビット プラットフォームでは、long 配列を int に入れるべきではありません。トラブルシューティングが難しいいくつかのバグが発生する可能性があります。したがって、zend_parse_parameter() 関数を通じてパラメータを受け取るときは、カーネルによってキャリアとして合意された型の変数を使用する必要があります。
パラメータはCのデータ型に対応します
b zend_bool
l long
d double
s char*, int 前者はポインタを受け取り、後者は長さを受け取ります
r zval*
a zval*
o zval*
O zval *, zend_class_entry*
z zval*
Z zval**
PHP 言語のすべての複合型パラメータは、カーネルによってカスタマイズされたデータ構造であるため、キャリアとして zval* 型を必要とすることに注意してください。パラメーターの型とキャリアが一貫していることを確認する必要があります。必要に応じて、配列を stdClass オブジェクトに変換するなど、型変換を実行できます。 s タイプと O (ヨーロッパの大文字) タイプは、両方とも 2 つのキャリアを必要とするため、別々に記述する必要があります。次の章では、PHP でのオブジェクトの具体的な実装について学習します。それでは、第 5 章で定義した関数を書き直してみましょう:
function sample_hello_world($name) {
echo "Hello $name!n"
}
拡張機能を記述するときは、zend_parse_parameters( ) を使用する必要があります。次の文字列を受け取ります:
ZEND_FUNCTION(sample_hello_world) {
char *name;
int name_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",&name, &name_len) == FAILURE)
{
RETURN_NULL( ; 実行失敗し、FAILURE が返されます。
複数のパラメータを受信する必要がある場合は、次のように zend_parse_paramenters() のパラメータに受信キャリアを直接リストすることができます:
function sample_hello_world($name, $greeting) {
echo "Hello $greeting $ name!n";
}
sample_hello_world('John Smith', 'Mr.');
これは PHP 拡張機能で実装する必要があります:
ZEND_FUNCTION(sample_hello_world) {
char *name;
int name_len;
char *greeting ;
挨拶文
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss",&name, &name_len, &greeting, &greeting_len) == FAILURE) {
ITE(greeting,greeting_len);
php_printf(" ");
PHPWRITE(name, name_len); php_printf("!n");
}
上記で定義されたパラメータに加えて、パラメータを受け取る機能を強化するために次の 3 つのパラメータがあります。
型修飾子の意味
|その後のパラメータはオプションです。つまり、デフォルト値があります。
! PHP 言語で null 変数を受け取った場合、IS_NULL 型の zval にカプセル化するのではなく、C 言語で直接 NULL に変換されます。
/ 渡された変数が他の変数と zval を共有し、参照ではない場合、新しい zval の is_ref__gc==0 と refcount__gc==1 が強制的に分離されます。続けて、sample_hello_world() を書き換えます。次に、いくつかのパラメータのデフォルト値を使用します。これは、PHP 言語で次のようになります。 ') {
echo "Hello $greeting $name!n";
}
sample_hello_world('Ginger Rogers','Ms.');
現時点では、1 つだけ渡すことができます。パラメータをsample_hello_worldに渡すことも、2つのパラメータ全体を渡すこともできます。 では、同じ機能を拡張関数に実装するにはどうすればよいでしょうか? zend_parse_parameters では (|) パラメータを使用する必要があります。このパラメータの前のパラメータは必須とみなされ、このパラメータが渡されない場合、キャリアは変更されません。
ZEND_FUNCTION(sample_hello_world) {
char *name;
int name_len;
char *greeting = "Mr./Mrs."
if ( zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
&name, &name_len, &greeting, &greeting_len) == FAILURE) {
RETURN_NULL()
}
php_printf("Hello "); );
php_printf(" ");
PHPWRITE(name, name_len);
php_printf("!n");
}
2 番目のパラメータを渡さない場合、拡張関数はキャリアを変更せずにデフォルトとみなされます。したがって、キャリアの値を自分で事前に設定する必要があります。多くの場合、これは NULL または関数ロジックに関連する値です。 IS_NULL タイプの zval を含む各 zval は、一定量のメモリ空間を占有する必要があり、CPU コンピューティング リソースがそれにメモリを適用し、初期化し、作業完了後に解放する必要があります。しかし、多くのコードはこれを認識していません。 null 値を zval の IS_NULL 型にラップするコードは数多くありますが、この操作は C 言語でパラメータを NULL として受け取ることができるため、拡張開発で最適化できます。この問題に関する次のコードを見てみましょう:
Zend_function(sample_arg_fullnull){zval *val; if (Z_TYPE_P(val) == IS_NULL) {
val = php_sample_make_defaultval(TSRMLS_C); }
...
}
ZEND_FUNCTION(sample_arg_nullok) {
zval *val; UM_ARGS() TSRMLS_CC, "z !」、
val(TSRMLS_C);2 つのコードは一見するとあまり違いがありませんが、最初のコードはより多くの CPU とメモリ リソースを必要とします。もしかしたらこのテクニックは普段はあまり役に立たないかもしれませんが、知らないよりは知っていた方が良いです。
強制分離
変数が関数に渡されると、それが参照されているかどうかに関係なく、その refcoung__gc 属性は 1 つ増加し、少なくとも 2 になります。 1 つのコピーはそれ自体であり、もう 1 つは関数に渡されるコピーです。この zval を変更する前に、事前に実際の 2 つのコピーに分割する必要がある場合があります。これは「/」フォーマット文字の役割です。これにより、コピーオンライト zval が事前に 2 つの完全な独立したコピーに分割されるため、次のコードで自由に操作できるようになります。そうしないと、受け取ったパラメータとその他の操作を分離することを常に自分自身に思い出させる必要があるかもしれません。 NULL フラグと同様に、この修飾子は影響を与える型の後に続きます。また、NULL フラグと同様に、この機能が必要かどうかは、実際に使用するまでわかりません。拡張機能が古いバージョンの PHP と互換性があるか、パラメータを受信するキャリアとして zval のみを使用したい場合は、zend_get_parameters() 関数を使用してパラメータを受信することを検討できます。 zend_get_parameters() は zend_parse_parameters() とは異なり、解析せずに直接取得します。まず、拡張実装のすべてのパラメーターのキャリアは zval 型である必要があります。
ZEND_FUNCTION(sample_onearg) {
zval *firstarg; firstarg.. . */
}
第二に、zend_get_parameters() は、受信が失敗したときに単独でエラーをスローすることはなく、デフォルト値のパラメーターを適切に処理することもできません。 最後の点は、コピーオンライトに準拠するすべての zval を自動的に強制的に分離し、新しいコピーを生成して関数に送信するという点で、zend_parse_parameters とは異なります。他の機能を使用したいが、この関数は必要ない場合は、zend_get_parameters_ex() 関数を使用してパラメータを受け取ることができます。 コピーオンライトの変数を分離しないように、zend_get_parameters_ex() のパラメータは zval* ではなく zval** 型になります。 この関数は、極端な問題が発生した場合にのみ使用される可能性がありますが、使い方は非常に簡単です。
zval **firstarg;
if (zend_get_parameters_ex(1, &firstarg)) == FAILURE) {
WRONG_PARAM_COUNT;
}
/* firstarg で何かを行う... */
}
zend_get_parameters_ex は後の段階で追加されるため、パラメータとして ZEND_NUM_ARGS() を必要としないことに注意してください。すでにNo moreになっています。
WRONG_PARAM_COUNT マクロは、上記の例でも使用されており、その機能は E_WARNING レベルのエラー メッセージをスローし、それを自動的に返すことです。
変数パラメーター
他に 2 つの zend_get_parameter_** 関数があります。これらは、多くのパラメーターの問題、または事前にパラメーターの数がわからない問題を解決するために特別に使用されます。 PHP 言語での var_dump() 関数の使用法を考えてみましょう。カーネルでのその実装は実際には次のようになります:
int i, argc = ZEND_NUM_ARGS() ;
zval ***args;
args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
if (ZEND_NUM_ARGS() == 0 || zend_get_parameters_array_ex(argc, args) = = FAILURE ] }
efree(args);
}
プログラムは最初にパラメータの数を取得し、次に、safe_emalloc 関数を通じて対応するサイズのメモリを適用して、これらの zval** 型パラメータを保存します。ここでは、zend_get_parameters_array_ex() 関数を使用して、関数に渡されたパラメータを args に埋め込みます。 zend_get_parameters_array() という関数もあるとすぐに思ったかもしれませんが、唯一の違いは、zval* 型パラメータを args に入力し、パラメータとして ZEND_NUM_ARGS() を必要とすることです。