PHPを中心に、エラーメッセージのアレコレ

# エラーメッセージのアレコレ

実装したAPIやログへエラーメッセージを残す場合について、
かなりざっくりと解説してみます。

もっとくわしくやりたいひとはこちらへ
https://www.php-fig.org/psr/psr-3/

まず、エラーとは
引用元：[wikipedia エラー](https://ja.wikipedia.org/wiki/エラー) 2018.07.05

>コンピュータの動作におけるエラーには、プログラム自身の文法的な誤りによってそれ以上の処理が続行できない状態と、与えられたデータ（情報）に誤りがあり処理が続行できない場合、あるいはオペレーティングシステム (OS) やコンピュータシステムがプログラムの要求に応じられない場合などに発生する。

そして、エラーメッセージとは
引用元：[wikipedia エラーメッセージ](https://ja.wikipedia.org/wiki/エラーメッセージ) 2018.07.05

>エラーメッセージは、アプリケーションソフトウェアやオペレーティングシステムなどのコンピュータプログラムが、エラーの発生などにより、所定の処理を続行できない旨をユーザーに通知する際に表示するものであるが、より広義には自動化された装置が規定の動作を行なえない場合に点灯させるインジケーターや警告ブザーなども、その意味においてはエラーメッセージである。なお本項では特に断りが無い場合は、主にコンピュータの動作においてユーザーに異常がある旨を通知するメッセージについて説明する。

>コンピュータの動作におけるエラーには、プログラム自身の文法的な誤りによってそれ以上の処理が続行できない状態と、与えられたデータ（情報）に誤りがあり処理が続行できない場合、あるいはオペレーティングシステム (OS) やコンピュータシステムがプログラムの要求に応じられない場合などに発生する。


# 結論から

## エラーメッセージは次のような感じで実装すると幸せ

+ ユーザー向けと、デバッグや障害対応向けに出し分けをしよう
+ お問い合わせ先やバグの自動報告機能を用意すると大変親切。
+ 「何をしようとしたら」「何が起こったか」をエラーの発生内容でちゃんと出力しよう
+ 操作や運用上で発生する場合、エラーコードとドキュメントを整備しよう
+ エラーの発生した時刻、アカウント、ファイル、行番号などを出力しよう
+ 出来ればエラーの発生した場合の処理経路と発生時の入力データを出力しよう

## PHPでエラーログやメッセージを作る上で便利なもの

+ マジック定数
   + [自動的に定義される定数](http://php.net/manual/ja/language.constants.predefined.php)
+ フォーマット
   + [```sprintf()```](http://php.net/manual/ja/function.sprintf.php) 
   + [```bin2hex()```](http://php.net/manual/ja/function.bin2hex.php)
+ [エラー処理関数](http://php.net/manual/ja/ref.errorfunc.php)
   + バックトレース [```debug_backtrace()```] (http://php.net/manual/ja/function.debug-backtrace.php)
   + システムエラーを発生させる [```trigger-error()```](http://php.net/manual/ja/function.trigger-error.php)
   + etc...
+ [例外処理](http://php.net/manual/ja/language.exceptions.php)
   + [カスタム例外](http://php.net/manual/ja/language.exceptions.extending.php)
+ その他
   + フレームワークごとのvalidator、例外、ログ出力など...
   + xdebugなどのデバッグツールの導入、設置

# 以下、悪い例などを交えて

## とても悪い例

```
エラーが発生しました。
```

そうだね！　エラーだね！　エラー処理があるだけマシか！！

この場合、もしかしたら、

+ ユーザーなどにエラーを表示してしまうとセキュリティ的によろしくない
+ エラー内容から余計なことを勘繰られたりしないための自衛策

とかの配慮かもしれません。

しかし、これでは発生点から追跡していかないといけませんし、
どんなエラーが発生したのか分かりません。

## だいぶ悪い例

```
エラーが発生しました。ドキュメントを参照してください。
```

エラーが発生した場合の何らかの対応や対策が用意されているようです。
修正時やAPIを利用して実装していく際にとても重要です。

でも、これだとドキュメントもどこを見ればいいか分からないね！！
~~このエラーを書いた人の頭もデバッグしたくなｒ~~

お問い合わせ先や、物理的にドキュメントがどこにあるかも分かりません。
~~もしかしたらドキュメントは古代の書物になって、
社内ダンジョンの一番奥に眠っているかもしれｍ。~~

## エラーコード入れてみた。

```
[3] エラーが発生しました。ドキュメントを参照してください。
```

いいね！　エラーコードいいね！
ドキュメントを文字列検索するか、索引を見れば分かるかもしれませんね。
でも、たぶん「3」ってイッパイ検索にヒットすると思う。

もしかしたらドキュメントに「エラーコード一覧」という親切なページが用意されているかも知れませんが、油断は禁物です。

## プレフィックス付き、ゼロパディングしたエラーコード入れてみた。

```
[ERR-004] エラーが発生しました。ドキュメントを参照してください。
```

プレフィックス（ERR-の部分）は、お好みで。
エラーコードはこれでいいんじゃないでしょうか。

きっと検索も簡単だし、~~邪悪な~~表計算ソフトで管理しても
ゼロパディングのおかげでだいぶ見やすくなってきた感じでしょう。
~~開発サイドで表計算ソフトで管理していたら私は逃げます~~

## エラーの内容を書いてみよう。

```
[ERR-004] ファイル作成処理に失敗しました。ドキュメントを参照してください。
```

そう！　これだよ！！
もうドキュメントを見たりしなくていい。
もういいんだ、君はよく頑張った......！！

もし、エラーの詳細が膨大な場合、エラーコードと紐づくドキュメントを用意して補足するなどしてもいいかもしれません。
しかし、これはまだ実装のどこで問題が起きてるかが分からないですし、どう修正や対応を行えばいいかわかりません。

## エラーが発生したファイルと行を表示してみる。

ここから少し開発やエンジニア寄りになります。

```
[ERR-004] ファイル作成処理に失敗しました。 (/server/www/hoge.php:32)
```
これでどこでエラーが起きたか追跡しやすくなりました。
だいぶエンジニアな感じになってきました。

新人エンジニアが「ふえぇ......ファイル作成処理ってどこでやってるの。また忙しそうな先輩エンジニアに話しかけなきゃいけないの:droplet:」とか、先輩エンジニアから「いや、ソースコード読めよ:anger:」とか仕打ちを受け、職場でウッカリとデュエルが始まる不幸もだいぶ回避できそうです。

しかし、ソースコードがサーバ上にしかなく、すぐに環境構築ができないとか、HotFixを投入しなければいけない状況では不利かもしれません。

## 例外などで補足していたエラーを表示する。

```
[ERR-004] ファイル作成処理に失敗しました。 ( Illuminate\\Queue\\MaxAttemptsExceededException(code: 0): hoge has been attempted too many times or run too long. The job may have previously timed out. at /server/www/hoge.php:32 )
```

とてもリッチで、直接ソースコードを見なくても、わかる人は何が起こってるか大体わかるようになってきました。

もしかしたら実装した人物や、どんな実装をしていて、どう直せばいいかも分かり「なんで自分はこんな実装をしたんだ......！」まで辿り着けることもあるかもしれません。
~~自分でやらかしてると、凹むよね。~~

## ここからはお好みで

例えばphpでは [```debug_backtrace()```](http://php.net/manual/ja/function.debug-backtrace.php) で呼び出し元のメソッドを追跡したり、メソッドの引数を取得することもできます。

また [```var_dump()```](http://php.net/manual/ja/function.var-dump.php) や [```var_export()```](http://php.net/manual/ja/function.var-export.php) でメソッドの入力値を出力させても良いかもしれません。