PHP5.3/6.0で参照カウンタを操作するマクロが変更されている件

いきなりIoバインディングコンパイルが通らなくなって何事かと思いきや、最新snapshotではZVAL_ADDREF, ZVAL_DELREF, ZVAL_REFCOUNTがなくなり、代わりに以下のようなマクロ郡が追加されていました。PZVAL_IS_REFは残っていますが、後述する理由により、PZVAL_IS_REF(zv) = 1; のような使い方はできなくなりました。

zval zval * zval ** 説明
Z_REFCOUNT(z) Z_REFCOUNT_P(pz) Z_REFCOUNT_PP(ppz) 参照カウントを返す
Z_SET_REFCOUNT(z, rc) Z_SET_REFCOUNT_P(pz, rc) Z_SET_REFCOUNT_PP(ppz, rc) 参照カウントを設定し、新しい値を返す
Z_ADDREF(z) Z_ADDREF_P(pz) Z_ADDREF_PP(ppz) 参照カウントをインクリメントし、新しい値を返す
Z_DELREF(z) Z_DELREF_P(pz) Z_DELREF_PP(ppz) 参照カウントをデクリメントし、新しい値を返す
Z_ISREF(z) Z_ISREF_P(pz) Z_ISREF_PP(ppz) is_refフラグの値を返す
Z_SET_ISREF(z) Z_SET_ISREF_P(pz) Z_SET_ISREF_PP(ppz) is_refフラグを真にし、新しい値を返す
Z_UNSET_ISREF(z) Z_UNSET_ISREF_P(pz) Z_UNSET_ISREF_PP(ppz) is_refフラグを偽にし、新しい値を返す
Z_SET_ISREF_TO(z, isref) Z_SET_ISREF_TO_P(pz, isref) Z_SET_ISREF_TO_PP(ppz, isref) is_refフラグを設定し、新しい値を返す

これらのマクロの実体はzvalリファレンスカウンタおよびis_refフラグを操作するインライン関数で、これまでPHPソースコードではZVAL_ADDREF等のマクロを使わずにzval構造体のメンバを直接操作しているのが散見されましたが、今後はそういったことはできなくなります。


ChangeLogにも書かれていますね。

2007-10-07  Yiduo (David) Wang  <planetbeing@gmail.com>

    * (PHP_5_3)
      zend.c
      (snip.)
      zend_vm_execute.skl:
      MFH: Added macros for managing zval refcounts and is_ref statuses

    * zend.c
      (snip.)
      zend_vm_execute.skl:
      Added macros for managing zval refcounts and is_ref statuses


これ自体はまっとうな仕様変更なのですが、旧APIとの互換性がなくなっているのでPHP 5.2以前にもPHP 5.3以降にも対応するエクステンションを書く場合は以下のようにマクロを定義しておいて、新しいAPIを使ってコードを書き直すのが良いかと思われます。

#ifndef Z_REFCOUNT_P

#define Z_REFCOUNT_PP(ppz)             ((*(ppz))->refcount)
#define Z_SET_REFCOUNT_PP(ppz, rc)     ((*(ppz))->refcount = rc)
#define Z_ADDREF_PP(ppz)             (++(*(ppz))->refcount)
#define Z_DELREF_PP(ppz)             (--(*(ppz))->refcount)
#define Z_ISREF_PP(ppz)                ((*(ppz))->is_ref)
#define Z_SET_ISREF_PP(ppz)            ((*(ppz))->is_ref = 1)
#define Z_UNSET_ISREF_PP(ppz)          ((*(ppz))->is_ref = 0)
#define Z_SET_ISREF_TO_PP(ppz, isref)  ((*(ppz))->is_ref = isref)

#define Z_REFCOUNT_P(pz)            ((pz)->refcount)
#define Z_SET_REFCOUNT_P(z, rc)     ((pz)->refcount = rc)
#define Z_ADDREF_P(pz)            (++(pz)->refcount)
#define Z_DELREF_P(pz)            (--(pz)->refcount)
#define Z_ISREF_P(pz)               ((pz)->is_ref)
#define Z_SET_ISREF_P(pz)           ((pz)->is_ref = 1)
#define Z_UNSET_ISREF_P(pz)         ((pz)->is_ref = 0)
#define Z_SET_ISREF_TO_P(z, isref)  ((pz)->is_ref = isref)

#define Z_REFCOUNT(z)             ((z).refcount)
#define Z_SET_REFCOUNT(z, rc)     ((z).refcount = rc)
#define Z_ADDREF(z)             (++(z).refcount)
#define Z_DELREF(z)             (--(z).refcount)
#define Z_ISREF(z)                ((z).is_ref)
#define Z_SET_ISREF(z)            ((z).is_ref = 1)
#define Z_UNSET_ISREF(z)          ((z).is_ref = 0)
#define Z_SET_ISREF_TO(z, isref)  ((z).is_ref = isref)

#endif