エラー処理を考察

前回の記事で、get_post_type_archive_link()関数の判定でエラー(false)が返ってきたら処理をしないということを学び、他の関数のエラー時の戻り値を色々眺めていました。すると、エラー時にfalseを返さずWP_Errorというクラスオブジェクトをそのままreturnしている関数を見かけたので調べてみました。

WP_Errorクラスを紐解く

なにはともあれ、まずはCodexでWP_Errorの仕様を確認。

WP_Error は、プラグインと WordPress 自身のエラー処理を簡単に行えるようにするクラス(PHP のクラス)です。
WP_Error のインスタンスは一つか複数のエラーを表すエラーコードとメッセージを保持します。 また、ある変数が WP_Error のインスタンスであるかをis_wp_error()関数を使って判定できます。

Codex日本語版クラスリファレンス/WP Errorの説明より引用

なるほど、任意のエラー情報を複数保持させたい時に使うのか。ちょうど今作っているフォームの入力チェックなんかで使えそう。ちょっと中身を確認。まずはWP_Errorクラスのコンストラクタが何をしているか見てみる。

public function __construct( $code = '', $message = '', $data = '' ) {
	if ( empty($code) )
		return;

	$this->errors[$code][] = $message;


	if ( ! empty($data) )
		$this->error_data[$code] = $data;
}

プロパティの配列$errors$error_dataにエラーコードをキーにしてメッセージとデータを渡しているんだ。これ、エラーメッセージが1つならこれで良いけど、それだとあまり利点を感じない。メソッドの中にadd()というのがある。これがコンストラクタと同じ処理しているな。

public function add($code, $message, $data = '') {
	$this->errors[$code][] = $message;
	if ( ! empty($data) )
		$this->error_data[$code] = $data;
}

add()メソッドはコンストラクタと違って$code$messageが必須なわけね。では、空のインスタンスを作ってエラーメッセージ分add()メソッドで追加するほうが美しいと思われる。ということで実験。

$error = new WP_Error();
$error->add( "name",    "姓が入力されていません。" );
$error->add( "name",    "名が入力されていません。" );
$error->add( "address", "住所が入力されていません。" );
var_dump( $error );

var_dump()で中身を確認してみると、以下の通り。

object(WP_Error)[5772]
  public 'errors' =>
    array (size=2)
      'name' =>
        array (size=2)
          0 => string '姓が入力されていません。' (length=36)
          1 => string '名が入力されていません。' (length=36)
      'address' =>
        array (size=1)
          0 => string '住所が入力されていません。' (length=36)
  public 'error_data' =>
    array (size=0)
      empty

$codeに「name」を渡すとコードがかぶることなく2次元配列に保存されていきます。これを取り出す時は、メソッドが準備してあるのでそれを使用。

get_error_messages($code)
すべてのエラーメッセージ、または指定したコードにマッチするエラーメッセージを取得します。パブリックにアクセス可能で、エラー文字列の配列を返します。指定したコードにマッチするメッセージが無ければ空の配列を返します。
get_error_message($code)
エラーメッセージを一つ取得します。指定したコードの最初のメッセージを返します。コードを指定しなければ、先頭のコードが使われます。エラー文字列を返します。
Codex日本語版クラスリファレンス/WP Errorの説明より引用

get_error_message()でエラーメッセージを一つ取得できるんだけど、「0」番目(0 => string ‘姓が入力されていません。’ (length=36))しか取れない……。名のエラーメッセージを取るには、get_error_messages()でエラー全部取って「1」番目を指定するしかないか。例えば、入力が空でないかのチェックするような内容で、ループで回せるようなら使えるか。うーん、通常は一つの$codeに対しては、一つのエラーメッセージという考え方のほうが良さそう。

$error = new WP_Error();
$error->add( "surname", "姓が入力されていません。" );
$error->add( "name",    "名が入力されていません。" );
$error->add( "address", "住所が入力されていません。" );

if ( empty( $surname ) ) {
	echo $error->get_error_message( "surname" );
}
if ( empty( $name ) ) {
	echo $error->get_error_message( "name" );
}
if ( empty( $address ) ) {
	echo $error->get_error_message( "address" );
}

まぁ、WP_Errorクラスの生成とエラー判定は別々のメソッドにしてあげればエラー処理に関するメッセージなんかを一元管理できそう。単純なエラー判定なら普通の条件文でも良いと思うんだけど、入力フォームのようにエラー判定がたくさんあるような場面であれば、こういうやり方のほうが美しい。それにWordPressは翻訳前提なので、まとめておいたほうが抜け漏れが無くなりそう。これは覚えておこう。