先日 PHP のメジャーバージョンである PHP7 がリリースされました。 性能向上のために内部構造が大きく変更されているため、PHP5 向けの拡張モジュールは大幅に書き直しが必要です。
拡張モジュールを開発したことがある人はご存知の通り、PHP の内部 API は公式の解説がほとんどありません。 必然、先人の資料や本体のコードを読み漁ってなんとかするわけで、以下の資料を大いに参考にいたしました。
- Upgrading PHP extensions from PHP5 to NG
公式のポーティング資料。これを読まないと始まらない。 - SWFEditor の PHP7 対応
@yoya 氏の詳細な対応資料。一番のポイントは PHP7 用コードを PHP5 と分ける点。 - PHP5とPHP7の違い(extension編)
@hnw 氏による資料。TSRMLS_*
マクロが不要になった、など。 - PHP: internals:engine:objects
カスタムクラスを作成する方法。PHP7 と直接関係はないが、PHP7 対応のついでにオブジェクトの実装方法を変えたので参照した。
実際の対応については、以下のようにしました。
- PHP5 と PHP7 でソースコードを分ける
Divide source code for PHP5 and 7. · cybozu/php-yrmcds@353f917 · GitHub
config.m4
で PHP のバージョンを検出して、PHP5 と PHP7 で別のソースコードをコンパイルするように。 - 変更されたと明記されている API をちまちま直す
TSRMLS_*
マクロの削除や文字列長の型をint
からsize_t
に修正するなど。 - クラスとリソースの実装を大幅に変更する
リソースをやめてオブジェクト内部にソケットを保持するように変更するなど。 ZEND_TSRMLS_CACHE_*
マクロを追加
ext_skel
の生成するスケルトンコードに追加されていたので、PHP7 のソースコードに追加。- コンパイルして、ほかに必要な API 変更がないか見てみる
ここまでの修正が済んでいれば、あと必要な変更はほんの少しだけではないかと思います。
私の場合、zend_register_internal_class_ex
の第三引数が PHP7 では不要になっていた、くらいでした。 make test
でテストを通す
もちろん PHP5 と PHP7 の両方で試します。
実はこれまで*.phpt
の形式にしていなかったのですが、いい機会なので大幅にテストを足しました。
PHP5 と PHP7 でソースコードを分けるか否か迷うかもしれませんが、もし拡張が内部クラスやリソース、あるいはハッシュテーブルの API を利用している場合、変更が大きすぎるので分けたほうが良いと思います。
最後に感想ですが、PHP7 の内部 API はすごく洗練されたのが作業を通じて理解できました。 PHP5 からのポーティングは大変面倒ですが、PHP7 向けに拡張を書くのはこれまでよりずっと合理的で理解しやすくなっていると思います。
雑なメモですが、どなたかのお役に立てば。