関数の作成
PHP では関数とメソッドはだいたい同じ形式で、メソッドは単にスコープが限定された関数でしかありません。
つまり、そのメソッドが属するクラスエントリのスコープになるということです。
クラスエントリについては、このマニュアルの別のページで説明します。
このセクションの目的は、関数やメソッドの内部構造を紹介することです。
関数を定義したり、変数を受け取ったり、PHP プログラマーに値を返したりする方法を説明します。
関数の内部構造は、それほど単純ではありません。
PHP_FUNCTION(hackers_function) {
/* 受け取る引数をここで指定します */
long number;
/* 引数を受け取ります */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &number) != SUCCESS) {
return;
}
/* 何かの作業をします */
number *= 2;
/* 戻り値を設定します */
RETURN_LONG(number);
}
プリプロセッサの PHP_FUNCTION(hackers_function) 命令は、
次のような宣言に展開されます。
void zif_hackers_function(INTERNAL_FUNCTION_PARAMETERS)
INTERNAL_FUNCTION_PARAMETERS はマクロとして定義されており、
次の表のようになります。
INTERNAL_FUNCTION_PARAMETERS
| 型と名前 |
説明 |
アクセス用マクロ |
int ht |
ユーザーから実際に渡されたパラメータの数 |
ZEND_NUM_ARGS() |
zval *return_value |
PHP 変数へのポインタ。ここに、ユーザーへの戻り値を設定します。
デフォルトの型は IS_NULL です。
|
RETVAL_*, RETURN_* |
zval **return_value_ptr |
PHP に参照を返すときには、ここに変数へのポインタを設定します。
参照を返すことはお勧めしません。
|
|
zval *this_ptr |
メソッド呼び出しの場合は、$this オブジェクトを保持する PHP 変数を指します。
|
getThis() |
int return_value_used |
返り値を呼び出し元が使うかどうかを示すフラグ。
|
|
明確にするために、完全に展開した PHP_FUNCTION(hackers_function) のドキュメントを示します。
void zif_hackers_function(int ht, zval* return_value, zval** return_value_ptr, zval* this_ptr, int return_value_used)
this_ptr の存在を奇妙に感じるかもしれません。クラスの詳細は後ほど説明するとして、ここでは
PHP_METHOD(MyClass, hackersFunction) の結果が次のような宣言になることを示しておけば十分でしょう。
void zim_MyClass_hackersFunction(INTERNAL_FUNCTION_PARAMETERS)
hackers_function は特に凝ったことをするわけではなく、zend_parse_parameters API
を使って受け取った数値を二倍して、それをエンジンに返すだけです。
普通は、単に入力を二倍するだけなどではなく、もっと複雑な何かを行うことでしょう。
ここでは、説明のために、できるだけシンプルにとどめました。
関数に入った際に return_value を確保し、null に初期化されます。
これで、PHP の関数のデフォルトの返り値が null となります。
Hacker が正しい引数として指定する内容を
zend_parse_parameters が受け取れず、受け取った引数を
type_spec を満たす形式に変換できなかった場合は、エラーを発生させます。
そして、Hacker はその場で return しなければいけません。
注意:
Array、Object、そして Resource は変換できません。
パラメータのプロトタイプのパース
int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...) |
int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...) |
int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...) |
注意:
zend_parse_parameter はバージョン 5.5 以降で使用可能で、zend_parse_parameters_ex と同じような挙動です。
ただ、引数をスタックから読み込むのではなく、変換対象の zval を受け取って、その場で変換します。
注意:
flags はマスクとして扱うことを想定しています。現時点で有効なフラグは ZEND_PARSE_PARAMS_QUIET だけです (これは、警告を抑制します)。
これらの API 関数から受け取る可変引数は、C の変数のアドレスであることが期待されています。
また、zend_parse_parameters API 関数の出力であると考えなければいけません。
型指定子
| 指定子 |
型 |
ローカル |
| a |
array |
zval* |
| A |
array あるいは object |
zval* |
| b |
boolean |
zend_bool |
| C |
class |
zend_class_entry* |
| d |
double |
double |
| f |
function |
zend_fcall_info*, zend_fcall_info_cache* |
| h |
array |
HashTable* |
| H |
array あるいは object |
HashTable* |
| l |
long |
long |
| L |
long (LONG_MAX/LONG_MIN の範囲に収まるもの) |
long |
| o |
object |
zval* |
| O |
object (指定した zend_class_entry のもの) |
zval*, zend_class_entry* |
| p |
string (有効なパス) |
char*, int |
| r |
resource |
zval* |
| s |
string |
char*, int |
| z |
mixed |
zval* |
| Z |
mixed |
zval** |
注意:
型指定子が O の場合、ローカルの zend_class_entry* は
zend_parse_parameter への入力 (型指定子の一部) と見なされます。
高度な型指定子
| 指定子 |
説明 |
| * |
直前の型の引数が 0 個以上 |
| + |
直前の型の引数が 1 個以上 |
| | |
残りのパラメータは任意である |
| / |
後に続くパラメータを SEPARATE_ZVAL_IF_NOT_REF します。 |
| ! |
直前のパラメータが、指定した型あるいは null のどちらかになるものとします。
'b'、'l'、'd' の場合は、対応する bool*、long*、double*
の後に zend_bool* 型の引数を追加する必要があります。null
を受け取った場合は、ここに true が設定されます。
|
注意:
パラメータのパースについての詳細は、ソース配布物に含まれる README.PARAMETER_PARSING_API を参照ください。
一度 Hacker の関数が実行されたら、実行するよう実装されているかどうかにかかわらず、エンジン向けの return_value を設定します。
RETURN_ マクロと RETVAL_ マクロは
Z_*_P の単なるラッパーで、return_value と組み合わせて使います。
注意:
RETURN_ マクロはその場で関数の実行を終了します (つまり、return; します) が、
RETVAL_ は、return_value を設定してからも実行を続けます。
これで、関数の仕組みについて、それなりに理解できたことでしょう。
メソッドの仕組みについても、ある程度は理解できたはずです。