PHPで関数の引数を別の関数に委譲(丸投げ)する方法
関数の委譲(デレゲーション)とは、外部からの受付は関数Aがやるけど、実際の処理は関数Bに委託してやってもらうことを言います。
なぜそんなことをするかというと「楽をするため」です(キッパリ!)。
「楽をする」ための関数
では「関数の委譲で楽ができる」ということをもう少し考えてみましょう。
登録ユーザーのプロフィールデータを取得する関数
よくWebシステムにおいては「登録ユーザーのデータをデータベースから取り出す」ということをやることがありますね。 仮にその関数を「getUserData()」という関数で実装したとします。 引数にはユーザーを特定するための検索条件を入れます。 すると返り値にユーザーデータを返します。
引数については、幾つになるか今後分からないので、func_num_args() で調べて func_get_arg() を使って関数内で取り出すようにします。
function getUserData() { if (func_num_args() > 0) $param = func_get_arg(0); ...(中略)... return $data; }
この場合の検索条件はよく複雑になりがちです。 SQL文を直接入れるかもしれないし、引数を複数定義することもあるでしょう。 どちらにしろ、厄介な処理の入り口でもあります。(笑)
ユーザーデータの中の最小限のデータを取得する関数を作りたい!
ところで、システムを組んでいると、ユーザーデータを取得しても、その中の多くのデータが必要ない場合がけっこうあります。 例えば「名前」と「ふりがな」だけとか。 それがいくつかの箇所で必要となると関数化したいですよね。
では、この関数を「getUserNameData()」という関数で定義するとして、どう書くか?
できれば以下のようにgetUserData()を再利用して取得したデータをフィルターして、住所情報、電話番号、メールアドレスを削除したいと思うでしょう。
function getUserNameData() { if (func_num_args() > 0) $param = func_get_arg(0); ...(中略)... $data = getUserData($param); unset($data['address']); unset($data['phone']); unset($data['email'); return $data; }
しかし、ここでなんとも気持ち悪い感じがする人、多いと思います。
そうです、引数の扱いがエレガントじゃない。
getUserNameData() は getUserData() に対して引数をまるごと渡したいのに、if文を使っていちいちチェックしないといけないのです。 なぜなら、処理を委譲する際に引数を漏れなく指定してあげないといけないからです。
この構成は非常に厄介です。 getUserData() に引数を渡す際に func_get_args() を使って引数リストを取り出し、そのまま渡せればいいのですが、仕様上それができません。
call_user_func_array() で引数を丸投げ委譲
そこで便利な関数を紹介。 「call_user_func_array()関数」です。 この関数の便利な所は、別の関数に渡す引数のリストを配列形式で渡すことができるところ。
これだと後で引数の型や数が変動しても、処理を委譲する場合にそのまま丸投げすることができるのです。 引数を丸投げで渡す際には func_get_args() で渡すことができます。
function getUserNameData() { $params = func_get_args(); $data = call_user_func_array('getUserData', $params); unset($data['address']); unset($data['phone']); unset($data['email'); return $data; }
もし渡す関数がクラス内に定義してある場合は以下のように call_user_func_array() の第一引数を配列型にして、クラスインスタンス(例えば $this)を指定します。
function getUserNameData() { $params = func_get_args(); $data = call_user_func_array(array($this, 'getUserData'), $params); unset($data['address']); unset($data['phone']); unset($data['email'); return $data; }
2011-04-09