2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
PHPのエラーを理解して適切なエラーハンドリングを学ぼう(全1記事)
リンクをコピー
記事をブックマーク
並里氏:では、PHPのエラーから学ぶ例外処理、エラーハンドリングのLTを始めたいと思います。よろしくお願いします。
まず1点、このLTの資料自体がPHPerKaigi 2022で話した20分の内容なので、少し駆け足になっていると思います。ご了承ください。よろしくお願いします。
目次です。「今回の対象者と話す内容」「エラーについて」「エラーハンドリングについて」「PHPの例外について」「エラーハンドリングを学ぶ」「振り返り」でやっていきたいと思います。
対象者は「そもそも、エラーハンドリングという言葉を知っているけど、何をするの?」という人だったり、「PHPのエラー? とりあえずいつもググってるよ!」という人。
(スライドを示して)話す内容は、エラーについて、(スライドに記載している)以下を話していきます。
一応、本内容での言葉を統一しておきます。「エラー=エラー処理」「エラーハンドリング=例外処理」「例外=Exception」というところで話していきます。
まずエラーについて。エラーは実行中のプログラムが正常に処理をできなくなるような問題・事態のことです。
PHPのエラーにはどういうものがあるかというと、大きく分類して「致命的なエラー」と「警告・注意」が存在します。致命的なエラーというのが「現在の処理を中断する=早く直せ」というような、実装者に向けたエラーですね。警告・注意は「現在の処理は中断しないけど、直したほうがいいよ」というレベルのエラーになります。
致命的なエラーの代表は、Fatal errorやParse errorがあります。
WarningやNoticeなどはphp.iniの設定次第で無視はできるのですが、バグの発生要因になるので、あまり推奨はしません。
次にエラーハンドリングについて話します。エラーハンドリングとはそもそもなにかというと、プログラムがエラーを起こした時に、すぐに実行を終了せずに、あらかじめ用意しておいた処理を行うこと。ユーザー操作によって解決できない問題があった場合に対処するための処理です。
PHPのエラーハンドリングについてですが、5系から導入されたtry-catchで記述していきます。例外が発生し得る箇所をtry {}で囲み、例外が発生した時点で後続する処理は中断され、catch {}で受け取り、例外が発生した時の対応(ハンドリング)を行います。例外を明示的に発生させたい場合は、該当する箇所でthrowを用いて例外を投げます。
PHPのエラーハンドリングの書き方です。(スライドを示して)こういうふうにtry {}で囲みます。try {}の中のif文ですが、ここでは例として、メールが重複していたらRuntimeException、拡張した例外を投げるという処理を書いています。
PHPの例外について少し話します。実は「PHPのエラー」で紹介した致命的なエラーなどの一部は、try-catchでは補足できません。方法はあるにはあります。ですがたいていの場合、それらは捕捉する必要自体がありません。次のページで簡単にPHPの例外について触れながら説明していきます。
(スライドを示して)ここも図が見づらくて申し訳ないのですが、5系まではすべての致命的エラーはエラーハンドリングができず、処理がそこで中断されてしまいます。しかし7系からは、Throwableインターフェースが実装され、それを継承したExceptionとErrorが導入されました。そのおかげで致命的エラーの多くがErrorをthrowするようになり、捕捉が可能になりました。
しかし、致命的なエラーのすべてがErrorに実装されたわけではないのが現状です。ごめんなさい。(スライドを示して)これは7系の時点なので、8系がどうなっているかは置いておきます。ですが先述したとおり、すべてを捕捉する必要はありません。
たいていのエラーはプログラムやFW(Frame Work)側が検知してくれているので、実装者は開発中に起きたエラーを修正するだけで済みます。そのためエラーハンドリングをする必要はありませんという意味です。
では、実際にエラーハンドリングを学んでいきます。「エラーハンドリングというものについて少しは理解できたけど、必要性は?」「どういう時に使えばいいの?」などの疑問が残っていると思います。なので、一つひとつQ&A方式で説明します。
まず「エラーハンドリングを使わないとどうなるの?」。1、エラーの発生箇所や原因の特定が難しくなる。2、エラー発生後も後続の処理が実行されてしまう。3、エラーが起きていることをユーザーが認知できない。
ここで、アンサーです。「エラーハンドリングはどんな時に用いるのか?」。繰り返しになりますが、1、エラーの発生箇所や原因の特定をしたい時。2、エラー発生後に後続の処理を中断させて、別の対応をしたい時。3、エラーが起きていることをユーザーに通知したい時です。
まず1の「エラーの発生箇所や原因の特定をしたい時」から説明します。
例外が発生した内容をcatch句で受け取り、メッセージなどをロギングしておけば、発生箇所や発生日時、原因の特定などが容易になります。そうすることで、エラーが起きた時にエラーのthrow の内容を見て即座に対応がしやすくなったりが可能になります。
2番「エラー発生後に後続の処理を中断させて別の対応をしたい時」。例外を受け取ったら処理を中断させて別の対応をしたい時は、ロギングの時と同様に、catch句の中で行いたい処理を書きます。その際、returnをしないと後続してしまうので、注意をお願いします。
では、3「エラーが起きていることをユーザーに認知したい時」。こちらも先ほどと同様に、catch句で例外を受け取ったら、呼び出し元やユーザーにreturnでエラーを通知するという内容を実装しています。この対応が抜けていると、ユーザーは処理が問題なく対処されたと認識されてしまいます。
ではちょっと別の質問です。「エラーハンドリングを考える上で大事なことは?」
1、例外を握り潰さない。2、エラーハンドリングのスコープは狭く。3、捕捉すべき例外とそうでない例外を理解しましょう。
ではまず1つ目の「例外を握り潰さない」。せっかく例外をthrowしても、catch句でなにもしなければエラーを無視しているも同然です。catch句ではロギングのほかに、エラーの発生を呼び出し元に伝える、後続の処理を行わないためにreturnするなど、要件に応じた対応をしましょう。
throwをせっかく投げてもcatch句でなにも書いてない状態を、“エラーを握り潰す”とか“例外を握り潰す”みたいに言うのですが、しっかり例外が発生したら呼び出し元に伝えたり、後続処理を行わないようにするなど、要件に応じて対応をお願いします。
2つ目「エラーハンドリングのスコープは小さく」。(スライドを示して)この図を見てもらうと、try {}の中にIfがいっぱいあったり、例外が書いてあると想定しています。さまざまな例外を全部1つのtry {}の中に収めて(しまい)、catchをすべてExceptionで拾ってしまっています。
tryの範囲が広いと、例外が発生した時の特定が難しくなります。catch句はすべてExceptionで受け取るのではなく、それぞれ適切な例外クラスを利用しましょう。
3つ目「捕捉すべき例外とそうでない例外」。捕捉すべき例外というのを3つ挙げています。「例外発生以後も処理が続けられてしまうと、データ不整合など障害につながってしまう時」「例外の発生後に呼び出し元やユーザーへの通知、ロギングなどを行いたい時」「例外発生前に行っている処理や状態をロールバックしたい時」が捕捉すべき例外と挙げています。
逆に捕捉すべきではない例外。開発時に対処できるタイプエラーなどの例外や、例外が発生してもその後の回復処理などが行えない時などは、また別の対応が必要になってくるかなと思います。
だいぶ駆け足になってきたので理解が追いついていない方もいると思うのですが、少し振り返りをします。
ここまで学んだエラーハンドリングを振り返ります。(スライドを示して)ここに例のコードを書いています。user -> insertPoint。ユーザーにまず1ポイントを付与するというところで、プログラムがあって、基幹システムにAPIでユーザーとポイント情報を渡す。
基幹システムにユーザーとポイント情報をAPIでpostしているが、なにかのエラーになって、ユーザーにはポイントが付与されたままになってしまう。この状態のままだと、なにかエラーがあっても、ユーザーにはポイントが付与されたことになってしまっています。
基幹システムへのAPIで成功したレスポンスが返ってこない場合に、例外をthrowして、ユーザーに対して付与していたポイントをロールバック。その後、開発者向けにロギングと通知、リダイレクトしてユーザーにエラーがあって、ポイントを付与できなかったことを伝える。
ここに書いてあるコードが、先ほど上で見た例外処理を実装したパターンになっています。
try {}の中でinsertPoint、ユーザーに1ポイント与える。その後、API通信が成功したかどうかを例外でcatchします。例外が発生した場合は、catch句でデータベースにまずロールバックを行って、ロギングしてSlackにエラー通知をする。ここではSlackを例に挙げています。最終的にユーザーにエラーが発生したことを伝えるため、エラーを表示といったところを簡単に実装した例です。
少し駆け足になってしまいましたが、私の発表は以上になります。ご清聴ありがとうございました。
関連タグ:
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05