ハッシュテーブルのチェイン法を見るまでの記事でデータ構造のハッシュテーブルを見た。
ハッシュテーブルはPHPの変数や関数の登録の際にも利用されているので、PHPのハッシュテーブルを見る。
ソースコードは今日現在のGitHub - php/php-src: The PHP Interpreterのソースコードとする。
早速、HashTableで検索をしたら、
php-src/Zend/zend_types.h
typedef struct _zend_array HashTable;
となっていた。
_zend_array構造体をHashTableと定義する?
更に読み進めてみると、
struct _zend_array {
zend_refcounted_h gc;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar flags,
zend_uchar _unused,
zend_uchar nIteratorsCount,
zend_uchar _unused2)
} v;
uint32_t flags;
} u;
uint32_t nTableMask;
Bucket *arData;
uint32_t nNumUsed;
uint32_t nNumOfElements;
uint32_t nTableSize;
uint32_t nInternalPointer;
zend_long nNextFreeElement;
dtor_func_t pDestructor;
};
/*
* HashTable Data Layout
* =====================
*
* +=============================+
* | HT_HASH(ht, ht->nTableMask) |
* | ... |
* | HT_HASH(ht, -1) |
* +-----------------------------+
* ht->arData ---> | Bucket[0] |
* | ... |
* | Bucket[ht->nTableSize-1] |
* +=============================+
*/
_zend_array構造体と一緒にハッシュテーブルのデータ構造の説明があった。
nTableMaskは難しい問題があるらしいので今は触れない事にして、もう一つのBucketの方に触れる。
typedef struct _Bucket {
zval val;
zend_ulong h; /* hash value (or numeric index) */
zend_string *key; /* string key or NULL for numerics */
} Bucket;
上記はBucket構造体で、ハッシュテーブルのチェイン法で見たようなnextの値等はない。
Bucketの値から何らかの方法でハッシュ値を計算して、arDataの任意の箇所にBucketを格納するという認識で間違いないだろうか?
typedef struct _Bucket {
zval val;
zend_ulong h; /* hash value (or numeric index) */
zend_string *key; /* string key or NULL for numerics */
} Bucket;
次にBucketの方を見る。
zvalの箇所に関数型のzvalをセットするということになるだろうから、それに該当するものを探してみる。
zvalはzend_valueを含む構造体であったので、
typedef union _zend_value {
zend_long lval; /* long value */
double dval; /* double value */
zend_refcounted *counted;
zend_string *str;
zend_array *arr;
zend_object *obj;
zend_resource *res;
zend_reference *ref;
zend_ast_ref *ast;
zval *zv;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
zend_valueの方を見ると、zend_valueは共用体であって、どれか一つのメンバを使用することになっていたはず。
zend_functionで検索してみると、
php-src/Zend/zend_compile.c
union _zend_function {
zend_uchar type; /* MUST be the first element of this struct! */
uint32_t quick_arg_flags;
struct {
zend_uchar type; /* never used */
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
uint32_t fn_flags;
zend_string *function_name;
zend_class_entry *scope;
zend_function *prototype;
uint32_t num_args;
uint32_t required_num_args;
zend_arg_info *arg_info; /* index -1 represents the return value info, if any */
HashTable *attributes;
} common;
zend_op_array op_array;
zend_internal_function internal_function;
};
共用体であった。
今の知識レベルだと、この共用体の解釈をどうすれば良いのかわからないので、今回はここまでにしておく。
今回の内容を整理すると、関数を登録するためのハッシュテーブルがあって、
HashTable - Bucket - zval - zend_value - zend_functionと関数を登録するだけでもいくつかデータをつなげている事がわかった。
わからない事が多いなと痛感する…





