ハッシュテーブルのチェイン法を見るまでの記事でデータ構造のハッシュテーブルを見た。
ハッシュテーブルは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と関数を登録するだけでもいくつかデータをつなげている事がわかった。
わからない事が多いなと痛感する…