なんてこと、たまにありますよね。
こんにちはテツバマツヘイです。寒い冬が終わり春がやってきましたね。 私は昨年3月末に上京し、Web事業企画開発本部で働き始めて早一年が経過しました。 上京してから運動不足だったこともあり最近仕事終わりと休日に水泳を始めました。 10年ぶりにしっかりと泳ぐので初回は水中で息継ぎして大量の水を吸ってしまうという恥ずかしい失敗をしました!
早速ですが、表題の件に戻りましょう。 今回はエラーが発生したときに行っている調査方法をお話させていただきます。 この記事を読み初学者の方がエラーに遭遇した時に、乗り越えるための一つの手段として思い出していただけると幸いです。 また、エラーを少しでも好きになっていただけると嬉しいです。
特定のボタンを押した時にエラーが出た場合
例えば、「画面上のフォームで文字を入力した後に保存ボタンを押す」というデータ追加処理を実装しているケースで、保存ボタンを押した時に保存ができていなかったりエラーになった場合、まずどうしますか。
①とりあえず分かりそうな方に問い合わせる ②時間を置くことでエラーが解消することを祈る ③原因を探す
恐らくみなさん③の原因を探すという行動を取られると思います。
では具体的に何をしたら良いのでしょうか。
バグやエラーの原因を特定する流れ
原因の特定は思ったよりも簡単で、以下の順序で行います。
エラー内容を読み原因箇所の当たりをつける その場で処理が止まるような処理を埋め込む エラーが発生した処理を実行する
では次は具体的にどのように行っているかをお話したいと思います。
どのように行うのか
実演用にLaravelで作ったアプリの画面を見ていきましょう。 下記画像は「ささやく」ボタンを押下することで、入力したテキストが保存され、下部の一覧に表示されるアプリです。
今回はこの「ささやく」ボタンを押した際に発生するエラーを例にお話します。 それでは「ささやく」ボタンを押してみましょう。
1. 当たりをつける
ボタンを押すと下記のエラーが表示されました。
まずは表示されたエラーを読みましょう。 「Call to undefined function App\Http\Controllers\Tweet\redirct()」 →『定義されていない「redirct()」メソッドが呼び出されました』と表示されてますね。
下を見てみるとどうもApp\Http\Controllers\Tweet\CreateControllerというファイルの20行目で発生してるようですね。
では実際のコードを見にいってみましょう。
コード下部の方に上のエラーで記載されている、「redirct()」がありますね。 今回の原因はタイポであることは明白ですが、一旦話を続けましょう。
class CreateController extends Controller { /** * Handle the incoming request. */ public function __invoke(CreateRequest $request) { $tweet = new Tweet; $tweet->user_id = $request->userId(); $tweet->content = $request->tweet(); $tweet->save(); return redirct()->route('tweet.index'); } }
2. その場で処理が止まるような処理を埋め込む
今回のような単純なエラーの場合はすぐに原因がつかめますが、例えばAの中でCのメソッドを呼んでいるBのメソッドを呼び出して....みたいな処理があった場合を考えてみてください。 どの部分に問題があるのかを見つけるのは簡単ではないですよね????
なので、どの部分までは処理がうまくいっているのかを確認して、箇所を特定できるようにやってみましょう。
Laravelには「dd()」や「var_dump() exit()」 や echo()」と「exit()」を組み合わせるなどの便利な機能が用意されており、処理の途中に組み込むことで、特定の箇所で処理を終了させられることができます。
思い出してください。プログラムは上から下に順に実行されます つまり、埋め込んだ箇所より後ろでエラーが発生しているということが分かります。
「ddd()」や「dd()」、「var_dump()」はオブジェクトの中身やクエリなど様々な情報を出力できるのでエラーの特定や開発の場面で利用するととても便利です。 一度調べて使用してみてください。
では実際にvar_dump()を埋めてみましょう。 今回は「redirct()」メソッドの中の処理でエラーが発生してると仮定してください。
class CreateController extends Controller { /** * Handle the incoming request. */ public function __invoke(CreateRequest $request) { $tweet = new Tweet; $tweet->user_id = $request->userId(); $tweet->content = $request->tweet(); $tweet->save(); var_dump('ここまでは正常ですよ'); exit(); ←ここに埋めました return redirct()->route('tweet.index'); }
3. エラーが発生した処理を実行する
2で「var_dump(); exit();」を埋め込んだので、再度「ささやく」ボタンを押してみましょう。 すると下の画像のようになり、エラー箇所に到達する前に処理が止まります。
ここからわかることは「$tweet()->save();」の処理までは問題なく実行できているので、それ以降の箇所に問題があるということです。
このように私は原因の調査をしています。
エラーを修正して動かしてみましょう
それではタイプミスを修正して、期待通りに動くかを確認してみましょう。
class CreateController extends Controller { /** * Handle the incoming request. */ public function __invoke(CreateRequest $request) { $tweet = new Tweet; $tweet->user_id = $request->userId(); $tweet->content = $request->tweet(); $tweet->save(); return redirect()->route('tweet.index'); ←「redirct()」から「redirect()」に修正 } }
ささやいた後に一覧が表示されるようになりました! 先述の通り「$tweet()->save();」の処理までは問題なく実行されていたので、 一覧に「18時一旦飯食べに行くかー」が表示されていますね!
エラーにならないが、不具合がある場合など
エラーになる場合は上述の対応で原因特定できると思います。 しかし中にはエラーは出ていないが、画面に出力したい内容や意図した処理がなされないなどのバグもありますよね。
その時は上で紹介した「ddd()」などのデバッグ用ヘルパー関数を使ってみましょう。
実際に見てみましょう。 今回は「ささやき」を一覧で表示する箇所に「ddd()」を埋め込みました。
class IndexController extends Controller { /** * Handle the incoming request. */ public function __invoke(Request $request, TweetService $tweetService) { $tweets = $tweetService->getTweets(); ddd($tweets->toArray()); return view('tweet.index') ->with('tweets', $tweets); } }
画面を更新すると、画像のようなページが表示されます。
下の方のDUMPSを見てみましょう!なんてことでしょう!
画面に表示されているものが、渡ってきているではありませんか。
また、取得処理に使われたクエリも確認できます!
他にも下記のように様々な役立つ情報を得られます。
- スタックトレースや停止箇所
- リクエストヘッダ、ボディ
- 通ったルートや、どのミドルウェアが適用されてるか
- ログインしているユーザーと実行環境
他にも
保存して画面遷移が生じて、開発中に何度もデータを作成しないといけない時に 「return」直前に「dd()」などを入れることで、渡っている値の確認なども容易になります。
おわりに
少しはエラーを好きになれたでしょうか? 私は最近、新しいエラーをみるとワクワクするようになってきました。
本日はLaravelを見本に方法をご紹介しましたが、他にも様々な方法や他の言語、フレームワークでも似たようなことができると思われます。 これからエラーが発生した時など、一度思い出してみていただけると幸いです。
\\『真のユーザーファーストでマーケットを創造する』仲間を募集中です!! //