実例で学ぶPHP拡張モジュールの作り方

第5回PHP 5.3の変更点(その1)

個人的な事情により前回の掲載から大変長い間が空いてしまいました。読者の皆様にはこの場を借りてお詫びいたします。

この2年と9ヶ月(!!)の間にPHPに起こった最も大きな出来事といえば、何といってもクロージャ等、待望の新機能が追加されたPHP 5.3の登場でしょう。本連載の再開にあたり、まずは筆者が実際の拡張モジュール開発で直面したPHP 5.3の変更点について書かせていただきます。

PHP 5.3での変更点

PHP 5.3でのZend Engineの変更のうち、拡張モジュール開発に影響しそうなものを以下にざっと挙げてみました。

  • 参照カウンタを操作するAPIの変更
  • いくつかの関数/マクロ定義の変更
  • 名前空間つきクラス/関数/定数のためのマクロ追加
  • 名前解決のためのAPI追加
  • エラーハンドリング周りの強化
  • いくつかのAPIが非推奨に

また、そのほかにも

  • 遅延静的束縛(Late Static Bindings)やgoto文のための構造体の拡張
  • コンパイラによる最適化に関する変更
  • セキュリティの向上

など、細かな変更は数多くありますので、気になる方はPHPのソースコードの差分を眺めてみると意外な発見があるかもしれません。

それでは、今回は参照カウンタを操作するAPIの変更について見てみます。拡張モジュールによっては、これによってコンパイルできなくなるものもある重要な変更点です。

参照カウンタを操作するAPIの変更

PHP 5.2まではリスト1のようなマクロでzval構造体(PHPの変数)の参照カウンタの値を操作していましたが、PHP 5.3ではリスト2のような関数を使うマクロに変更されています。これによって、マクロを使わずに直接参照カウンタの値を操作することが不可能になりました。

リスト1 PHP 5.2までの参照カウンタ/参照フラグ操作API(Zend/zend.h)
#define ZVAL_ADDREF(pz)     (++(pz)->refcount)
#define ZVAL_DELREF(pz)     (--(pz)->refcount)
#define ZVAL_REFCOUNT(pz)   ((pz)->refcount)
#define PZVAL_IS_REF(z)     ((z)->is_ref)
リスト2 PHP 5.3の参照カウンタ/参照フラグ操作API(Zend/zend.h)
#define Z_REFCOUNT_P(pz)            zval_refcount_p(pz)
#define Z_SET_REFCOUNT_P(pz, rc)    zval_set_refcount_p(pz, rc)
#define Z_ADDREF_P(pz)              zval_addref_p(pz)
#define Z_DELREF_P(pz)              zval_delref_p(pz)
#define Z_ISREF_P(pz)               zval_isref_p(pz)
#define Z_SET_ISREF_P(pz)           zval_set_isref_p(pz)
#define Z_UNSET_ISREF_P(pz)         zval_unset_isref_p(pz)
#define Z_SET_ISREF_TO_P(pz, isref) zval_set_isref_to_p(pz, isref)
#define PZVAL_IS_REF(z)             Z_ISREF_P(z)

リスト1、2の関数マクロはzval構造体のポインタ(pz)を引数にとりますが、PHP 5.3ではさらにポインタのポインタをとるもの(接尾辞⁠_P⁠の代わりに⁠_PP⁠⁠)や構造体をとるもの(接尾辞⁠_P⁠なし)も追加されています。

この変更への対策は、単に新しいマクロを使うようにするだけです。もしPHP 5.3に対応しつつ、以前のバージョンとも互換性がある拡張モジュールを作りたいなら、リスト3のようなマクロを定義しましょう。

リスト3 後方互換用マクロ
#ifndef Z_REFCOUNT_P
#define Z_REFCOUNT_P(pz)            ZVAL_REFCOUNT(pz)
#define Z_SET_REFCOUNT_P(pz, rc)    (pz)->refcount = (rc)
#define Z_ADDREF_P(pz)              ZVAL_ADDREF(pz)
#define Z_DELREF_P(pz)              ZVAL_DELREF(pz)
#define Z_ISREF_P(pz)               PZVAL_IS_REF(pz)
#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(pz, isref) (pz)->is_ref = (isref)
#endif

次回予告

次回も引き続き、筆者が直面したPHP 5.3の変更点を紹介します。それ以後はPHP 5.3を基準として実際に拡張モジュールを作りながら、PHPのバージョン違いによる影響を受ける箇所について適宜解説する予定です。

おすすめ記事

記事・ニュース一覧