PHP7.4からPHP8.0にアップグレード、バグが顕在化して動かない例
PHPプログラムをcronでスケジュール実行しています。PHP7からPHP8にアップグレードすることで速度アップするメリットがあるようなので気軽にPHP8に変更しました。ひっそりとPHPプログラムが異常終了していました。
ソースコードレビューでチェックしたいポイントは以下3点です。
徹底してやっても、$_SERVERの例でわかるように、実際動作させることで止まってわかることもあるかと思います。これ困りますよね。使ってる変数も、実環境で値を取得して明らかにした上でレビューするしかないかも。
PHP7.4までは記述ミスではない限り、大抵どんな異常なデータでも受け止めてくれた。分厚い筋肉に覆われていて力強い、コンクリートかよ!そんな印象を持っています。
PHP8以降は簡単に倒れてしまいます。猫ぱんちで倒れます。
コンパイルでエラーチェックする方法やコンソールにエラーを出力する方法はあるんでしょうか?正常系はなんとか修正できました。
配列が[]の状態でmax()で落ちるとか結構処理内容に依存してしまうので困っていますよ。
exceptionでエラーが出ていればラッキーなんですが、そんな出力なく、die()している感じです。
IDEでphpデバッグ環境を整えていないので、このような状況でIDEでデバッグができるのか?よくわかっていません。
もっとスマートに見つける方法が知りたいですね。
変数の初期化は必須。nullを許容しない関数がたくさん増えました。
例えばcount関数はログ出力しないで落ちるなど、無言で終了するので致命的です。function a(){
if( 条件 ){$list[] = "a";}
if( count($list) ){ echo "ok"; }
}a();
条件を満たさない場合、$listは未定義(不定値)になります。
配列以外をcount関数に渡すと無言で落ちます。
count関数の他、利用する機会の多いarray_key_exists関数などでも同様です。異常な四則演算はスルーしません。無言で終了します。
error_reporting(-1);
echo 1 + v().PHP_EOL;
echo 1 - v().PHP_EOL;
echo 1 / v().PHP_EOL;
echo 1 * v().PHP_EOL;
function v(){
return "---";
}
PHP8では初めの+で終了します。PHP7.4はこのような異常な四則演算でも結果を返してくれます。1
1
INF
0
バグが顕在化して動かなくなるってことですね。それでも無言終了は困ります。空配列でmin,maxは動きません。無言で終了します。
error_reporting(-1);
echo "min".'"'.min([]).'"'.PHP_EOL;
echo "max".'"'.max([]).'"'.PHP_EOL;
echo "sum".'"'.array_sum([]).'"'.PHP_EOL;
PHP8ではmin([])で終了します(array_sumは動作します)。PHP7.4は以下のようにとりあえず動作します。min""
max""
sum"0"配列を受け付けない関数が増えています。無言で終了します。
$_SERVER変数を表示する単純なプログラムは動きません。foreach( $_SERVER as $key => $val ){
echo '<li>' . $key . ":" . urlencode($val) . "</li>";
}
URLに?x=a等設定で、$_SERVER['argv']=["x=a"]という配列が格納されていました。
上記ループで配列を引数に渡すとurlencodeの箇所で終了します。
まさか単純な処理で落ちるとは考えが及ばず、時間ロスしました・・・
事例から見えてきた修正のポイント
ソースコードレビューでチェックしたいポイントは以下3点です。
PHP標準関数の引数、処理の流れで引数に不正なものがないかをチェックする
配列を求めている関数に不定値を含めて配列以外を渡すのはNGです。
文字列を求めている関数に配列を渡すのはNGです(不定値はとりあえず動作するようです)。
PHP8は厳密です。四則演算(余りを求める含む)で文字列を渡すパターンがないかをチェックする
functionやメソッドの戻り値を使った四則演算を重点的にチェックしたいですね。min関数、max関数(Math関数は注意が必要かも)へ空配列が渡るパターンがないかをチェックする
countでチェックして、1件以上ある場合のみ使っているかチェックが必要です(必ずデータがある場合は含みません)。
徹底してやっても、$_SERVERの例でわかるように、実際動作させることで止まってわかることもあるかと思います。これ困りますよね。使ってる変数も、実環境で値を取得して明らかにした上でレビューするしかないかも。
まとめ:PHP8は打たれ弱い印象です。
PHP7.4までは記述ミスではない限り、大抵どんな異常なデータでも受け止めてくれた。分厚い筋肉に覆われていて力強い、コンクリートかよ!そんな印象を持っています。
PHP8以降は簡単に倒れてしまいます。猫ぱんちで倒れます。
コンパイルでエラーチェックする方法やコンソールにエラーを出力する方法はあるんでしょうか?正常系はなんとか修正できました。
配列が[]の状態でmax()で落ちるとか結構処理内容に依存してしまうので困っていますよ。
補足:どうやって特定しているの?ブロック単位でechoしています。
exceptionでエラーが出ていればラッキーなんですが、そんな出力なく、die()している感じです。
IDEでphpデバッグ環境を整えていないので、このような状況でIDEでデバッグができるのか?よくわかっていません。
- 1)いつもとは違うログ出力の箇所から止まっているソースを特定します。
でもどこで止まっているのかはわかりません。PHP7では動いていたんですから・・・ - 2)特定するため、一連の処理のブロック単位(例えば、先頭とreturn 前)でecho "適当な文字";を追加します。
php8でいつもの処理を実行します。通過している箇所はechoで出力されます。途中で止まったブロックを特定します。
このブロックを特定し、修正しても、その先でまた止まる可能性があります。全部特定するまで残しておくと後戻り少なく済みます。 - 3)特定したブロックで、さらにecho "任意の文字";で止まる場所を特定します。
こうやって絞り込んで終了している箇所を特定しました。
もっとスマートに見つける方法が知りたいですね。
- 初期費用0円(2022年8月4日に撤廃)
- 安定したサイト運営が可能(CPU/メモリ リソース保証 6コア/8GB〜)
- 契約中は独自ドメインつき 独自ドメイン永久無料特典があります
- 最大10日間無料で、サーバーのお試し利用ができます
- ディスクキャッシュも高速 NVMe SSDを採用(300GB〜)
- 大量アクセスでも安心 転送量は無制限
【このカテゴリーの最新記事】
-
no image
-
no image
-
no image
-
no image
-
no image
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/11447089
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック