自己責任でPHP7のcount()関数を改造してエラー抑制する


Parameter must be an array or an object that implements Countable

古いPHPのプログラムをPHP7.2以降で動かして、上記エラーの山に呆然となった人も多いことでしょう。
私もそうです。

プログラムをgrepしてみたら、数100か所でcount()関数が使われていました。
それらに全部countableな値が渡されているのかチェックするのは苦痛でしたし、書き換えの事を考えると吐きそうです。

新しい関数を作ったとしても、count()関数を使っている箇所全てを書き直さないといけません。

一括置換をかけたいのですが、困ったことに
select count(*) from…
とか恐ろしい記述があったりします。

php.ini等で、warning抑制という荒業もありますが、
私はその環境で関発出来る自信がありません。

try~catchで捕捉しようかとも思いましたが、
既存のファイル構造上めんどくさそうでした。

てか、なんで互換モードとかないんだろう…。

ネットで検索しても、「これだ!!」という解決策は見つかりませんでした。

というわけで・・・

自己責任でPHP本体を改造します!!

これは

  • PHPのバージョンは、7.4.3
  • 同じサーバで他のWEBサイトが動いてないこと
  • PHPがソースコードからのコンパイルでインストールされていること
  • トラブルが起きても他人のせいにしないこと

が、前提条件となっています。

条件を満たせない場合は、
素直に「is_countable」で検索してください。

エラーを出さないこともできるのですが、今回は
E_WARNINGE_NOTICE に変える改造をします。
別にE_DEPRECATEDでもいいと思います。
php.ini等でエラー出力を制御できればいいです。

対象ファイルは、

  • Zend/zend_vm_def.h(書き換え1か所)
  • Zend/zend_vm_execute.h(書き換え3か所)
  • ext/standard/array.c(書き換え3か所)

の3ファイルです。

Zend/zend_vm_def.h, Zend/zend_vm_execute.h の書き換え箇所は、

zend_error(E_WARNING, "%s(): Parameter must be an array or an object that implements Countable", opline->extended_value ? "sizeof" : "count");

これを、

zend_error(E_NOTICE, "%s(): Parameter must be an array or an object that implements Countable", opline->extended_value ? "sizeof" : "count");

に書き換えます。(E_WARNING → E_NOTICE)
多分コメントアウトしてしまえば、NOTICEすら発生しません。(試してない)

ext/standard/array.c は、

php_error_docref(NULL, E_WARNING, "Parameter must be an array or an object that implements Countable");

これを、

php_error_docref(NULL, E_NOTICE, "Parameter must be an array or an object that implements Countable");

に書き換えます。(E_WARNING → E_NOTICE)

あとは念のため、make clean して再インストールします。
怖いのでmake test はしません。

make clean
./configure {オプション自由}
make
make install

あとは、

<?php print count(NULL); ?>

などして、WARNINGが発生しないことを確認してください。
(php.ini の設定などで、メッセージの出力等は異なります。)

count(null); // 0
count(1); // 1
count('abc'); // 1
count(new stdclass); // 1
count([1,2]); // 2

WARNING無しでPHP5と同じ結果が出るようになりました。(NOTICEは発生してる)

当然ですが、公式では非推奨です。

多分、これやるとPHPコミュニティにすっげぇ怒られます。

バージョンアップをするときは、毎回同じ改造が必要です。

くどいようですが、本当に、
自己責任
でやりましょう。

というわけで、patch簡単に作れるんですが、
作らないでおきます。

他、undefinedが出るような関数

自分で定義して互換動作させてます。
mysql関数とか、ereg()関数とか。
いろいろ問題ありそうだけど…。