somemo programming etc.

プログラマ、雑記、プログラミング関係はLinkから、数式はこっちでまとめていることが多い

【php】エラー・例外のハンドリング【cakePHP】

エラーに関するまとめです。

ハンドリング関数

以下の2つです。

set_error_handlerはエラーが発生した場合に、set_exception_handlerはキャッチされなかった例外を処理する関数・メソッドを指定します。

set_error_handler

set_error_handlerは、処理するエラーレベルを指定することができます。trigger_errorで発生させたエラーも拾い処理してくれます。ただし、E_ERRORは処理できません。処理する前に、処理が止まってしまうためです。その場合の処理は、register_shutdown_functionで行えるようです。

set_exception_handler

set_exception_handlerは、キャッチされなかった例外を処理するので、各ソース全般で実装しなければならないSQLエラーやDBエラーなどを一括で実装できるようになります。

cakePHPでの体験

例外について取り上げた理由は、cakePHPでの開発において前述したSQL・DBエラーのハンドリングを実装したためです。PHP4に対応しているcakePHPでは例外をデフォルトで考えていません。

特に一番の問題だったのが、PDOを採用していないことです。これにより、DBエラーなのかSQLエラー等が発生しても検索結果を取得できなかったなどと区別がつきません・・・。

また、cakePHPのmodelメソッドによって検索結果0件のときに「false, null, array()」と返ってくる値がばらばらです。

さらに、queryメソッドやfindByfindAllなどを使用していると、区別の仕様が無い状態でした。加えてビヘイビアとpagerもあるので困難です。

今回行った対処方法

  • 各具象modelと抽象model(model.php)の間に自作モデルを挟んだ
  • 自作モデルに例外投げるかどうかを決めるプロパティとメソッドを用意した
  • 上記プロパティにより、例外を投げるか結果を返すかを判断するメソッドを用意した
  • オーバーライドできるメソッドをオーバーライドする
  • オーバーライドしたメソッドは、上記の例外or結果を返すメソッドを実行する
  • queryメソッドは、親クラスと同様にfunc_get_argsを使用している。指定したメソッドはmodel.phpのqueryメソッドにしました。(5.3でないのため、インスタンスメソッドにも拘らず、クラスメソッドとして実行します・・・)
  • findBy~は、call__メソッド(modelが継承しているOverloadableで呼ばれるマジックメソッド__callを経由して)呼ばれるので、call__もオーバーライドした
  • call__メソッドは、ModelBehavior::dispatchMethodを呼んで規則に合えば呼ぶように設定されている。また、自作したBehaviorがあれば、そのメソッドも呼ぶ。
  • よって、findで始まるメソッドであるかを判断して、例外を投げるか結果を返すかを実装した
  • つまり、findで始まるメソッドをBehaviorに実装してはいけない規約ができてしまった・・・
  • pagerの場合、controllerのpaginateに設定されたものをpaginate()で実行する。普通であれば、findのcountとallを実行する。
  • このときに、findを実行するモデルはfrom句の最初に指定したmodelになるので、そのモデルに例外設定等を行う必要がある。そしてpaginate()の引数として渡す。
  • 今回は主要なメソッドしか使っていないですが、cakePHPに詳しいなら内部でfindを実行しているメソッド(readなどなど)を使用するはずなので、今後そうなった場合まずい

まとめ

きちんと設計をせずに便利そうだからと簡単に実装しないことですね・・・