web-dev-qa-db-ja.com

関数呼び出しと単一配列の複数の引数

一連のパラメーターを受け取り、SQLクエリの条件としてそれらに適用する関数があります。ただし、条件自体を含む単一の引数配列を優先しましたが、

_function searchQuery($params = array()) {
    foreach($params as $param => $value) {
        switch ($param) {
            case 'name':
                $query->where('name', $value);
                break;
            case 'phone':
                $query->join('phone');
                $query->where('phone', $value);
                break;
        }
    }
}
_

私の同僚は、代わりにすべての引数を明示的にリストすることを好みました:

_function searchQuery($name = '', $phone = '') {
    if ($name) {
        $query->where('name', $value);
    }

    if ($phone) {
        $query->join('phone');
        $query->where('phone', $value);
    }
}
_

彼の主張は、引数を明示的にリストすることにより、関数の動作がより明白になるということでした-謎の引数_$param_が何であるかを見つけるためにコードを掘り下げる必要があるのとは対照的です。

私の問題は、10以上のような多くの引数を処理するときに、これが非常に冗長になることでした。推奨される方法はありますか?私の最悪のシナリオは、次のようなものです。

searchQuery('', '', '', '', '', '', '', '', '', '', '', '', 'search_query')

24
xiankai

私の同僚は上記の例に適しています。あなたの好みは簡潔かもしれませんが、それはまた読みにくく、そのため保守性が低くなります。そもそもなぜ関数を書くのが面倒なのか、あなたの関数は何を「テーブルに持っていく」のか、という質問をしてください。私はそれが何をするのか、そしてそれをどのように行うのか、それを使うためだけに非常に詳細に理解しなければなりません。彼の例では、私はPHPプログラマーではありませんが、関数の宣言で十分に詳細を見ることができるので、その実装に自分自身を気にする必要はありません。

引数の数が多い限り、通常はコードのにおいと見なされます。通常、関数はやりすぎをしていますか?多数の引数が本当に必要な場合は、それらが何らかの方法で関連付けられており、1つまたはいくつかの構造またはクラス(おそらく住所の行などの関連アイテムの配列)に属している可能性があります。ただし、非構造化配列を渡しても、コードの臭いに対処することはできません。

27
mattnz

私の答えは多かれ少なかれ言語にとらわれないです。

複雑なデータ構造(テーブル、レコード、ディクショナリ、オブジェクト...)で引数をグループ化する唯一の目的が、それらを全体として関数に渡すことである場合は、回避することをお勧めします。これにより、役に立たない複雑なレイヤーが追加され、意図がわかりにくくなります。

グループ化された引数がそれ自体で意味を持つ場合、その複雑なレイヤーは設計全体の理解に役立ちます。代わりに抽象化レイヤーと名付けます。

12個の個別の引数や1つの大きな配列の代わりに、相関データをグループ化する2つまたは3つの引数を使用するのが最良の設計であることに気付くでしょう。

4
mouviciel

あなたの場合は、同僚の方法がいいと思います。あなたがモデルを書いていて、私があなたのモデルを使ってそれらを開発していたなら。同僚のメソッドのシグネチャが表示され、すぐに使用できます。

一方、searchQuery関数の実装を調べて、関数が期待するパラメーターを確認する必要があります。

searchQueryが単一のテーブル内のみの検索に制限されているため、結合がない場合にのみ、このアプローチをお勧めします。その場合、私の関数は次のようになります。

function searchQuery($params = array()) {
    foreach($params as $param => $value) {
        $query->where($param, $value);
    }
} 

そのため、配列の要素が実際には特定のtableの列名であることをすぐに知っています。このメソッドを持つクラスがコードで表しています。

1
Ozair Kafray

両方を実行してください。 array_mergeは、同僚の好みに応じて、関数の上部に明示的なリストを許可する一方で、必要に応じてパラメーターが扱いにくくならないようにします。

また、質問のコメントから@chiborgの提案を使用することを強くお勧めします-あなたが意図していることがはるかに明確です。

function searchQuery($params = array()) {
    $defaults = array(
        'name' => '',
        'phone' => '',
        ....
    );
    $params = array_merge($defaults, $params);

    if(!empty($params['name'])) {
        $query->where('name', $params['name']);
    }
    if (!empty($params['phone'])) {
        $query->join('phone');
        $query->where('phone', $params['phone']);
    }
    ....
}
1
Izkata

また、クエリ文字列に似た文字列を渡し、 parse_str (PHPを使用しているようですが、他の言語で他のソリューションが利用できる可能性があるため)メソッド内の配列に処理します。

/**
 * Executes a search in the DB with the constraints specified in the $queryString
 * @var $queryString string The search parameters in a query string format (ie
 *      "foo=abc&bar=hello"
 * @return ResultSet the result set of performing the query
 */
function searchQuery($queryString) {
  $params = parse_str($queryString);
  if (isset($params['name'])) {
    $query->where('name', $params['name']);
  }
  if (isset($params['phone'])) {
    $query->join('phone');
    $query->where('phone', $params['phone']);
  }
  ...

  return ...;
}

そしてそれを

$result = searchQuery('name=foo&phone=555-123-456');

http_build_query 連想配列から文字列に変換します(parse_strします)。

0