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_WARNING を E_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()関数とか。
いろいろ問題ありそうだけど…。