🐘 片付けを忘れたサーバー
STAGE 3 ― 途中で止まる処理 ―
クリア 0 / 3
STAGE 3

途中で止まる処理

エラーと後片付け
🎯 ミッション
エラーで処理が途中で止まるとやりかけの準備が残ることを説明し、必ず後片付けをする書き方(finally)と、準備が全部終わってから「できた」の印をつける順番が大切な理由を説明できれば合格。
未達成
ねこ博士
前回、メモリ不足になるとPHPはリクエストを途中で打ち切る、という話をしたね。今日は「途中で止まる」とき何が起きるかを考えよう。メモリ不足に限らず、プログラムはいろいろなエラーで途中で止まる。
うさ美
たとえば、どんなエラーですか?
ねこ博士
読もうとしたファイルがない、0で割り算をした、時間がかかりすぎて打ち切られた、などだ。こういうとき、プログラムは続きの命令を実行せずに、エラーを処理する場所まで一気に戻る。料理の途中で火災報知器が鳴って、作業を放り出して非常口へ向かうようなものだ。
うさ美
放り出された作業は、どうなるんですか?
ねこ博士
そこが問題なんだ。具体的に考えよう。お客さんの名簿を作る処理があるとする。手順は3つだ。
① 名簿用の箱を借りる
② 箱に名前を1人ずつ書く
③ 書いた人数を「人数欄」に書く
そして最後に、使い終わった箱を返す。
名簿を作る3つの手順の途中でエラーが起きると、処理は残りの手順をとばしてエラーを処理する場所へ戻る。最後に書いてあった「箱を返す」も実行されず、借りた箱が返されないまま残る
うさ美
②の途中でエラーが起きたら、③と「箱を返す」がとばされてしまいますね。箱は借りっぱなしになります。
ねこ博士
そう。借りっぱなしの箱が少しずつたまっていくのをメモリリーク(漏れ)という。漏れが続くと、いずれ棚が足りなくなる。だから、多くのプログラミング言語には「エラーが起きても起きなくても、必ず最後にこれを実行する」という書き方が用意されている。PHPでは finally と書く。
try { // ① 箱を借りる ② 名前を書く ③ 人数を書く 名簿を作る(); } finally { // エラーで途中終了しても、ここは必ず実行される 箱を返す(); }
うさ美
finally に書いておけば、非常口に向かう前に必ず箱を返してくれるんですね。
ねこ博士
その通り。それに、PHPには前に話した「リクエストが終わったら区画の箱をまとめて返す」しくみもある。だから、返し忘れの漏れはリクエストの終わりに回収される。ここまではいいね。
うさ美
はい。
ねこ博士
では、もう1つの問題を考えよう。片付けの係は、名簿を片付けるときに「人数欄」を見て、何人分の箱を片付ければいいかを決めるとする。②の途中でエラーが起きたら、人数欄には何が入っているかな?
うさ美
③は実行されていないので、人数欄にはまだ何も書かれていません。でも、前回の話だと、借りた箱には前に使った人の中身が残っているんでした。ということは、人数欄には前の誰かが残した数が入っているということですか?
ねこ博士
そう。まだ書いていない欄には、意味のない古い数が入っている。これをゴミと呼ぶことが多い。片付けの係がそのゴミの数を「人数」だと信じたら、どうなると思う?
うさ美
実際より多い人数分を片付けようとして、名簿ではない、ほかの箱まで触ってしまうかもしれません。
ねこ博士
そうなんだ。片付けの係が、ほかの処理の箱を書き換えたり返したりしてしまう。これがメモリの中身が壊れる、ということだ。プログラムの動きは、そこから先、予想できなくなる。
うさ美
どうすれば防げるんですか?
ねこ博士
2つの考え方がある。1つは、箱を借りたらすぐに空っぽの初期値(たとえば人数0)を書いてから使い始めること。もう1つは、準備が全部終わってから「できた」の印をつけ、片付けの係は印のついたものだけを片付けることだ。
うさ美
準備が半分のものは、「できた」の印がないから、片付けの係は中身を信じない、ということですか?
ねこ博士
そう。準備の途中でエラーが起きても、片付けの係が判断に使う情報だけは、いつも正しい状態にしておく。これはプログラムを安全に作るための大事な原則なんだ。
💡 C言語の「非常口」PHP自体は C言語というプログラミング言語で書かれている。C言語には finally のような「必ず後片付けをする」しくみがなく、エラーのときに処理の途中から一気に別の場所へ飛ぶ setjmp/longjmp という道具がある。速くて便利だが、飛ぶ前にやりかけていた準備や片付けは、すべてプログラマーが自分で面倒を見なければならない。
【このステージの成果】 エラーが起きると、プログラムは残りの命令をとばしてエラーを処理する場所へ戻る とばされた「箱を返す」は実行されない → 借りっぱなし=メモリリーク。finally で必ず後片付けをする まだ書いていない欄には前の中身(ゴミ)が入っている。片付けの係がそれを信じると、ほかの箱を壊す 原則:借りたらすぐ初期値を書く/準備が全部終わってから「できた」の印をつける

確認クイズ

Q1. 処理の途中でエラーが起きたとき、ふつうのプログラムの動きは?

Q2. finally に書いた処理は、いつ実行される?

Q3. 準備の途中でエラーが起きても、片付けの係が間違えないようにするには?

← トップへ