scribble.yuyat.jp

PHP の zval を読む #2

Posted at 08 Jan 2012

今回の記事では GitHub における php/php-srccommit c5d10ddda394b573dfaea1380285e1dd5f3c0d50 を前提としている.

前回に引き続き zval 構造体について調べる.
今回は PHP におけるデータ型について調べて行きたい.

./Zend/zend.h を適当に眺めていると, 以下のような定数があった.

#define IS_NULL   0
#define IS_LONG   1
#define IS_DOUBLE 2
#define IS_BOOL   3
#define IS_ARRAY  4
#define IS_OBJECT 5
#define IS_STRING 6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_ARRAY 9
#define IS_CALLABLE 10

恐らく PHP の基本的なデータ型に対応していると思われる.
PHP 5.4 なので callable もある.
CONSTANT_ARRAY というのは何だろう.

とりあえずは IS_ARRAY がどのように使われているか調べてみることにする.

git grep するとたくさん出てくるので, 検索範囲を絞ってみることにする.
PHP の標準関数の中で, zval や IS_ARRAY がどのように使われてみるか調べてみよう.

標準関数は ./ext/standard ディレクトリ内で定義されている.
参考: PHPソースコードリーディング入門(とっかかり編) - id:anatooのブログ

./ext/standard/array.c の中を探していると, 以下のような関数が見つかった.

static int php_count_recursive(zval *array, long mode TSRMLS_DC)
{
    long cnt = 0;
    zval **element;

    if (Z_TYPE_P(array) == IS_ARRAY) {
        if (Z_ARRVAL_P(array)->nApplyCount > 1) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
            return 0;
        }

        cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
        if (mode == COUNT_RECURSIVE) {
            HashPosition pos;

            for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
                zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS;                                                                                                                    zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)
            ) {
                Z_ARRVAL_P(array)->nApplyCount++;
                cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC);
                Z_ARRVAL_P(array)->nApplyCount--;
            }
        }
    }

    return cnt;
}

これは PHP 標準の count() 関数の内部で呼ばれている関数である.
if (Z_TYPE_P(array) == IS_ARRAY) という記述から, Z_TYPE_P は zval のポインタを渡してその型を調べるためのマクロだと思われる.

Z_TYPE_P は ./Zend/zend_operators.h で定義されていた.

#define Z_TYPE(zval)    (zval).type
#define Z_TYPE_P(zval_p)  Z_TYPE(*zval_p)

Z_TYPE_P が zval のポインタから型を調べるためのマクロで, その内部では zval の値から型を調べる Z_TYPE マクロが呼ばれている.
そしてこの Z_TYPE マクロは zval の type メンバを読み出してだけである.

というわけで, 前回の記事と総合して, zval の type メンバは PHP におけるデータ型を保持している, ということがわかった.

続く?

Home