- 例としてPHPの例外を上げているが、大体どの言語でも通用する話。
例外の基本
- トランザクションの処理のところでは誰でも例外を使ってと思う
try {
db:save(User)
db:save(Plan)
db:commit
} catch {
db:rollback
}
PHPの例外
自分で作る例外はLogicExceptionかRuntimeExceptionを継承したもが大体になると思う
-
phpのエラーとExceptionは何が違うの?
Exception とは対極に, PHP処理系内部あるいはPHP処理系が持つ標準関数との互換性を強く意識したPHPコードで用いられます.
- 自分で実装する時はErrorを継承することはあんまりなさそう
try, catchとは
- tryで例外が発生したらcatchする
- tryの中で通常の動作でない、例外的なことが起こったらハンドリングしたい
- 処理の先で例外的なことが起こったらError, Exceptionをthrowする
- フレームワークだけじゃなくて、実装者が例外を投げることもあるの?
- よくある。
- csvで読み込んだデータの値がおかしい時とかになんで失敗したのかがわかるようなログを出したり
- システム的には問題なくても、ビジネスロジック的におかしな値が入力された時、
- 例えば、UserNameは空文字ダメ、3文字以上じゃないとダメ、みたいなルールがあれば、ルールに則っていない引数が渡された場合には例外を投げるとか
class UserName {
__constructor($userName: string) {
if (!($userNameが空文字やnullじゃないか && $userNameの文字数は3文字以上か)) {
throw new InvalidArgumentException('引数の値がおかしいよ')
}
}
}
- キャッチしたらどうするの?
try {
new UserName()
new UserId()
} catch {
// なんかログを出すとか、
// キャッチしたら再throwする
// 握り潰したらだめ
// 握り潰してしまうとどこで例外が発生したのかもわからないまま動き続けてしまう
}
-
実際には今回のUserNameの例だと、catchせずにフレームワークに任せて処理を止めてしまってもいい
- 大体のフレームワークは最終的にフレームワークで例外をキャッチしてエラーメッセージを出してくれたりする
-
再throwしたらどうするの?
- エラー画面出すとか
- フレームワークとかなら最終的にキャッチしてくれる
フレームワークではドメインレベルの例外については対応してくれないので、自分たちでthrowする必要がある
-
throwは言ってみればモダンなgoto文
- なので使い方には注意
- エラーじゃないのに便利だからって例外を投げるのはダメ
- 例外を投げるのは例外的なことが起こった場合のみ
- if文の代わりにthrowするのはダメ
例外の設計の話
例外をどこでキャッチしてる?
- フレームワークに任せるか、ControllerまたはUseCaseでキャッチしている
- FW Core ●
- Controller ●
- UseCase ●
- Domain
- Domain
- Domain
- Controller
- 基本はControllerでキャッチしてる
- 自作の例外は大体Controllerでキャッチ
- ログを出したり、ユーザーにお知らせしたり
- 基本はControllerでキャッチしてる
- UseCase
- foreach文の中とかで例外がはかれても処理を続けて欲しい場合はUseCaseでキャッチしてる
- そしてログを出したり
- foreach文の中とかで例外がはかれても処理を続けて欲しい場合はUseCaseでキャッチしてる
-
FW
- FWまで届くのはこれ以上処理が続けられないような例外
- フレームワークや言語の例外
- AWSのDB落ちてるとか
- FWまで届くのはこれ以上処理が続けられないような例外
-
プロジェクト固有のLogicExceptionとRuntimeExceptionを継承した例外クラスを作っておく
- 自分でthrowする時はこの2つか、継承したクラスを投げることが多い