結論から書くと、PHP のエラーログに出る Warning や Deprecated は、画面が動いていても放置しないほうがよい記録です。Warning は想定外の値のまま処理が続いていること、Deprecated は将来のバージョンで動かなくなる書き方を使っていることを示します。全部を一度に直す必要はなく、ログを数えて、処理が止まるもの、業務データに関わるもの、移行先で動かなくなるものの順に 直します。
この記事では、レンタルサーバーで PHP を切り替えた直後の切り分け(元に戻す手順、症状ごとの原因、ログの出力先の設定)、サポート切れ PHP のリスク、Laravel 固有のログの読み方は扱いません。前の2つは「レンタルサーバーで PHP のバージョンを切り替えたら動かなくなったときの切り分け」と「サポート切れ PHP を放置するリスクと、対応の優先順位」で説明しています。
Fatal error・Warning・Notice・Deprecated の意味と、今起きていること
PHP のエラーの種類は、公式マニュアルで E_ で始まる定数として決められています。ログには「PHP Warning:」のように種類の名前が付いて記録されます。
| ログでの表示 | 処理は止まるか | 今起きていること |
|---|---|---|
| Fatal error、Parse error | 止まる | 回復できないエラーや構文の誤りで、処理が終わった |
| Warning | 止まらない | 想定外の状態のまま、処理が先へ進んでいる |
| Notice | 止まらない | エラーかもしれないことが起きた。通常の処理でも起こり得る |
| Deprecated | 止まらない | 将来のバージョンで動かなくなる書き方を使っている |
「Fatal error: Uncaught」は、例外(処理を中断して異常を知らせる仕組み)がどこでも受け止められないまま、プログラムが終了したことを示します。
公式マニュアルのエラー処理の説明のとおり、Fatal error 以外の多くのエラーは処理を止めないため、画面に問題が見えないまま記録だけが増えます。
また、error_reporting(報告するエラーの種類の設定)の既定値は PHP 8.0 で変わり、それまで報告されなかった Notice と Deprecated も報告されるようになりました。この設定を指定していないシステムでは、8 系に上げるとこの2種類がログに出始めます。逆に、設定で Deprecated を外しているサーバーでは、8 系でもログに出ません。ログに無くても、直す箇所が無いとは限りません(確かめ方は後の節で説明します)。
放置するとどうなるか
今は止まらないものが、次のバージョンで止まる
前述のエラー処理の説明のとおり、エラーの扱いはバージョンの間で変わり、処理を止めるエラーへ格上げされることもあります。
| 書き方 | PHP 7.2 | PHP 8.0 |
|---|---|---|
定義されていない定数(固定の値の名前)を書く。例: 配列のキーを引用符で囲まない $row[name] |
Warning(Error 例外になると予告) | Error 例外で止まる |
数えられない値(値が無いことを表す null など)を count() に渡す |
Warning | TypeError で止まる |
8.0 の移行ガイドには、ほかにも「Warning から Error 例外へ」「Notice から Warning へ」変わった項目の一覧があり、配列に無いキーの読み取りは後者に入っています。目にしやすい Deprecated は次のとおりです。
- 8.1: 組み込み関数の、null を受け付けない引数に null を渡す(
Passing null to parameterを含むメッセージ) - 8.2: クラスで宣言していないプロパティ(オブジェクトが持つ値)を作る
- 8.4:
function foo(T $a = null)のように、引数の型に null を含めずに既定値を null にする書き方 - 8.5: null を配列のキーに使う、
(int)ではなく(integer)と書く型変換
Warning は、想定外の値のまま処理が続いている
配列に無いキーを読むと、PHP 8.0 以降では Warning(7 系までは Notice)が出て、値は null として扱われ、処理は続きます(配列の説明)。金額や数量を読む処理なら、値が無いまま計算や保存が進み、誤った値がデータベースに残り得ます。業務データを扱う処理で出ている Warning(7 系では Notice)は、データの不整合の兆候になり得ます。
件数を数えて、直す順番を決める
まず、ログを種類ごと、メッセージと場所ごとに数えます。次の例は、1行が「[日時] PHP Warning: メッセージ in ファイル on line 行番号」の形のログの場合です。書式は設定で変わるので、実際のログに合わせて調整します。
# 種類ごとの件数
grep -oE 'PHP (Fatal error|Parse error|Warning|Notice|Deprecated)' /path/to/php_error.log \
| sort | uniq -c | sort -rn
# メッセージと場所ごとの件数(先頭の日時を除き、多い順に30件)
grep -E 'PHP (Warning|Notice|Deprecated)' /path/to/php_error.log \
| sed -E 's/^\[[^]]*\] //' \
| sort | uniq -c | sort -rn | head -30
コマンドが使えない場合は、ログのファイルをダウンロードして表計算ソフトで数えても構いません。
同じ場所から繰り返し出ているものは、1か所直せばまとめて消えます。ただ、件数の多さと重要さは別です。順番は次の4段階で決めます。
- Fatal error と Parse error(「Fatal error: Uncaught」を含む)。 処理が止まっています。件数が少なくても最初に直します。
- 業務データに関わる Warning(7 系では Notice)。 金額・数量・日付・顧客の情報を扱う処理のものです。保存済みのデータに誤りが無いかも確かめます。
- 移行先のバージョンで削除・エラーになる Deprecated。 上げる予定のバージョンの移行ガイドと照らして選び、バージョンアップの作業の中で直します。
- それ以外。 件数の多いものから直し、ログを読める量に減らします。同じ Warning が大量にあると、新しく出た Fatal error が埋もれるためです。
vendor などライブラリのディレクトリで出ているものは、直接直さず、ライブラリの更新で対応します。ログには直す前の行も残るので、直した後は、直した日時より後の行だけを取り出して同じコマンドで数え直し、件数を記録しておきます。
@ や error_reporting で隠すのはどうか
@ 演算子。 式の前に @ を付けると、その式のエラーが抑止されます。処理を止めるエラーは PHP 8.0 から隠れなくなりましたが、Warning は今も隠れます。使うのは、失敗を想定し、その場で結果を確かめている箇所に限ります。
error_reporting。 前述のエラー処理の説明は、本番では E_ALL & ~E_NOTICE & ~E_DEPRECATED まで減らしてもよいが、多くの場合は E_ALL が適切、としています。phpinfo()(PHP の設定を表示する関数)の表示などで今の error_reporting を確かめ(表示用のファイルは確認後に削除します)、Deprecated が外れていれば、検証環境を E_ALL で動かして洗い出します。
どちらも、隠してもログが減るだけで原因は残ります。隠してよいのは画面への表示だけで、ログへの記録は残します。本番で画面にエラーを出すと、ファイル名や行番号など攻撃に利用され得る情報を見せることになるためです。表示を止めてログに残す設定は、冒頭で挙げた PHP の切り替えの記事で説明しています。
h-system でできること
h-system では、他社や前任者が作った PHP・Laravel のシステムの保守と、PHP のバージョンアップを開発者本人がお引き受けしています。バージョンアップでは、新しいバージョンで動かなくなる箇所(削除・非推奨になった関数や書き方、ライブラリの対応状況)を洗い出し、コードとライブラリを修正して、検証用の環境で動作を確認します。まず現状を確かめる調査だけのご依頼も可能です。初回のご相談と概算のお見積りは無料で、詳細な調査は有償です。範囲と費用は着手前にご案内します。