10.文字列の扱い

10.1.文字列の内部構造

 zval における文字列データは、zend_string として保持されます。zend_string は Zend/zend_types.h により以下のように実装されています。

typedef struct _zend_string     zend_string;

struct _zend_string {
  zend_refcounted_h gc;
  zend_ulong        h;                /* hash value */
  size_t            len;
  char              val[1];
};

typedef struct _zend_refcounted_h {
  uint32_t         refcount;      /* reference counter 32-bit */
  union {
    struct {
      ZEND_ENDIAN_LOHI_3(
        zend_uchar    type,
        zend_uchar    flags,    /* used for strings & objects */
        uint16_t      gc_info)  /* keeps GC root number (or 0) and color */
    } v;
    uint32_t type_info;
  } u;
} zend_refcounted_h;
_images/10-1-zend_string.png

 単純なコピーに代表される、文字列の中身の変更を伴わない参照の場合、同一の zend_string 領域を複数の zval が指すようにすることで、無駄なメモリコピーが抑えられ、処理速度の向上が見込めます。refcount は、この文字列が何個の zval から参照されているのかを示すカウンターです。refcount がゼロになると、自動的にメモリの開放が行われます。

10.2.文字列関連マクロ

 文字列に関するマクロやインライン関数は Zend/zend_string.h で定義されています。

文字列関連マクロ - ショートカット
No. マクロ宣言 定義 意味
1 ZSTR_VAL(zstr) (zstr)->val 文字列の実体(の先頭アドレス)
2 ZSTR_LEN(zstr) (zstr)->len 文字列の長さ
3 ZSTR_H(zstr) (zstr)->h ハッシュ値
4 ZSTR_HASH(zstr) zend_string_hash_val(zstr) (後述)

 ハッシュ値は、当該システムにおいて、文字列を一意に識別するための整数値です。これにより文字列を高速に検索できるようになっています。

10.3.インライン関数

 多数のインライン関数が用意されています。関数宣言において、冗長な部分は記載を省略しています。

文字列関連のインライン関数
No. 関数宣言 意味
1
zend_ulong
zend_string_hash_val(zend_string *s)
・ハッシュ値が未計算なら計算・保存する
・ハッシュ値を返す
2
void
zend_string_forget_hash_val(zend_string *s)
ハッシュ値をクリアする
3
uint32_t
zend_string_refcount(const zend_string *s)
文字列のリファレンスカウントを返す(*1)
4
uint32_t
zend_string_addref(zend_string *s)
リファレンスカウントをインクリメントして返す(*1)
5
uint32_t
zend_string_delref(zend_string *s)
リファレンスカウントをデクリメントして返す(*1)
6
zend_string
*zend_string_alloc(size_t len, int persistent)
文字列用の領域を確保して返す
7
zend_string
*zend_string_safe_alloc
(size_t n, size_t m, size_t l, int persistent)
文字列用の領域を確保して返す(詳細調査中)

(力尽きたので、いったんここまでで公開します)

  • (*1)…いずれも拘束文字列('interned string')の場合は 1 を返します。拘束文字列として定義された zend_string は、HashTable に保存する際に複製されません。