PHP 拡張のコンパイルで PHP_FE_END undeclared here

初めに断っておくと、古い PHP を残してしまう悪しきドキュメントです。
# とはいえ、PHP 5.3.x の x を固定にしてセキュリティパッチで延命する事もありそうなので。

はじめに

たまたま、この PHP 拡張を試そうとして*1思い出したのですが、

(特に野良の) PHP拡張をコンパイルする時に結構な頻度で PHP_FE_END でエラーになります。

/home/yoya/git/php-xz/xz.c:69: error: ‘PHP_FE_END’ undeclared here (not in a function)

これへの模範的な解答は、 PHP 5.4 か、ダメでも PHP 5.3.x の最新版 x に今すぐ上げろ! ですが、そうすぐには上げられない人向けに、以下に原因と対策です。

エラーの原因

PHP 拡張で zend_function_entry の終端は、PHP 5.3.6 までは

zend_function_entry xxx_functions[] = {
        PHP_FE(xxx_yyy,             arginfo_xxx_yyy)
        <略>
        {NULL, NULL, NULL}

という書き方でしたが、PHP 5.3.7 から

zend_function_entry xxx_functions[] = {
        PHP_FE(xxx_yyy,             arginfo_xxx_yyy)
        <略>
        PHP_FE_END

このように変わりました。

要するに

PHP 5.3.7 以降用に書かれた PHP 拡張のプログラムを
PHP 5.3.6 以前の環境で build しようとすると、
PHP_FE_END undeclared のエラーが出ます。

PHP のヘッダ

PHP_FE_END の定義は、

php-5.3.7/Zend/zend_API.h:#define ZEND_FE_END            { NULL, NULL, NULL, 0, 0 }
php-5.3.7/main/php.h:#define PHP_FE_END      ZEND_FE_END

PHP 5.3.6 と PHP 5.3.7 で grep すると、5.3.7 で定義が追加された事が分かります。

yoya@sakura:~/src/php$ grep -r PHP_FE_END php-5.3.6 | grep ".h:"
yoya@sakura:~/src/php$ grep -r PHP_FE_END php-5.3.7 | grep ".h:"
php-5.3.7/main/php.h:#define PHP_FE_END      ZEND_FE_END
yoya@sakura:~/src/php$

対策

真面目にやるならバージョンを見て切り替えをする王道を進むのが良いでしょう。

#if (defined(PHP_VERSION_ID) && PHP_VERSION_ID >= 50307)
    PHP_FE_END
#else
    {NULL, NULL, NULL}
#endif
    • PHP_VERSION_ID は 5.2.7 で導入されたものなので defined でのチェックが必要。

あと、身も蓋もない方法ですが自分で define しても勿論コンパイル出来ます。
何処にも commit しないコードならこんな感じで手抜きするのも手です。

#ifndef PHP_FE_END
#define PHP_FE_END {NULL, NULL, NULL}
#endif PHP_FE_END

筋は悪いですけど、あと20秒で build してインストールしないと世界が滅びる!
なんてシチュエーションがもしあれば使えば良いと思います。

*1:ちなみに xz ファイルや lzma ファイルを xzopen, xzread してみたけど "" が返ってきました。残念。