基本的な型での扱いについて
まずは、数値や文字列、BOOL値の扱い方を紹介します。これらの型がPHP上の最も基本的な型となり、これらの型を利用した基本的な関数の作成を示します。
PHPの型とエクステンション側の型について
PHP側の型とエクステンション側の型は完全に一致しているわけではありません。特に、数値の場合には注意が必要になります。
以下の関数は入力された数値(int型)をそのまま、戻り値として返す関数です。
PHP_FUNCTION(hellofunc_int){ long arg_num; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg_num) == FAILURE ){ return; } RETURN_LONG(arg_num); }
今回も同様にPHPで記述した場合を示します。
function hellofunc_int($val){ return $val; }
しかし、正確にはPHPで定義した関数とエクステンションとして定義した関数は異なる動作をします。PHPでは数値という漠然とした型で扱えます。実際にはint型やfloat型として扱われますが、それらは自動的にPHP側で制御してしまっています。ただし、C言語側ではそれをdouble型かlong型として認識させる必要があります。PHPでのint型はC言語側ではlongとして扱い、小数点などを含む数値のfloat型はC言語側ではdouble型として扱い処理をします。
PHP_FUNCTION(hellofunc_double){ double arg_num; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &arg_num) == FAILURE ){ return; } RETURN_DOUBLE(arg_num); }
PHPは型を問わない言語ではありますが、実際には、文字列型、整数型、浮動小数点型、BOOL型、配列、null型、オブジェクト、リソースなどがあります。これらに応じて、引数からの値の変換方法や、戻り値の指定方法があります。
引数の取得方法
引数を取得する場合には、zend_parse_parameters()関数を使います。この関数はPHPで引数を取得する場合に非常に便利な機能を提供してくれる関数で、データの変換を行ってくれます。実際に利用するには第1引数に実行時の引数の数、第2引数に型の指定を記述し、第3引数以降に実際に取得する変数を指定します。第3以降の変数は取得する型によって引数の数も種類も違います。また、TSRMLS_CCというマクロは、PHPをマルチスレッドとして動作させる時に有効になるマクロです。
以下に、よく利用する型のサンプルと一覧を示します。
// BOOL型 zend_bool b; zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b" , &b); // 文字列型 char *arg = NULL; int arg_len; zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s" , &arg, &arg_len); // 数値(long)型 long arg_num; zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &arg_num);
このように、型ごとに引数の数も変わってきます。
指定文字(第2引数) | タイプ | 代入数変数の型(第3引数以降) |
---|---|---|
a | array | zval* |
b | boolean | zend_bool |
d | double | double |
f | function | zend_fcall_info*, zend_fcall_info_cache* |
h | array | HashTable* |
l | long | long |
o | objects | zval* |
O | object(class定義したとき) | zval*,zend_class_entry* |
r | resource | char* |
z | mixed | zval* |
これ以外にも、PHPのマニュアルを参照することで、そのすべてが分かります。
戻り値の設定方法
関数の戻り値であるretrun_valueの正体は、zvalという構造体です。このzval構造体がPHPでいうmixed形式を実現しており、Zend/zend.hにその定義が記されています。
typedef struct _zval_struct zval; struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; zend_uchar type; /* active type */ zend_uchar is_ref__gc; };
このように、値(zvalue_value)と型(type)をもった構造体となっています。また、値にはさまざまな型としてアクセスできるように、以下のような定義となっています。
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ zend_object_value obj; } zvalue_value;
このあたりは前述したRETURN_STRINGLのマクロ展開からも推測ができると思います。関数からの戻り値を設定する場合に、時にはこれらについて詳しく知る必要がある場合もありますが、通常は以下のマクロを使用します。
戻り値の型 | 使用するマクロ | 備考 |
---|---|---|
NULL | RETURN_NULL() | |
BOOL | RETURN_BOOL(int b) | |
BOOL | RETURN_TRUE | RETURN_BOOL(1)と同様 |
BOOL | RETURN_FALSE | RETURN_BOOL(0)と同様 |
文字列 | RETURN_STRING(char *s, int dup) | 指定した文字列を返す |
文字列 | RETURN_STRINGL(char *s, int l, int dup) | 指定した長さの文字列を返す |
文字列 | RETURN_EMPTY_STRING( ) | 空文字を返す |
数値(long) | RETURN_LONG(long l) | |
数値(double) | RETURN_DOUBLE(double d) |
また、戻り値を設定するマクロには、RETVAL_BOOL(int b)のように上記表に対応するRETURN_*ではなく、RETVAL_*のようなマクロも存在します。これは、RETURN_*マクロがreturnを行いそれ以降実行しないのに対して、RETVAL_*はそのまま処理を実行します。従って、メモリの解放など後処理を行いたい場合にはRETVAL_*を使う必要があります。
最後に
今回は引数の扱い方と戻り値の基礎について扱いました。このような基本的な流れとルールが理解できると、既存のソースコードを読んだときに何となく意味が分かってくるのではないかと思います。また、これらの内容についてマニュアルで整備されている部分は少ないため、さまざまなサイトを参照し、情報を探すといったケースもあるかもしれません。しかし、必要な情報が載っているサイトというのは、あまり多くはないのです。そんなときは、PHPで既存の似た関数を探して、そのソースを参照するのがもっともよい方法です。
次回は配列の引数や戻り値、そして、複数の引数を取る場合を説明し、より複雑な関数の作成方法について説明を行います。