web-dev-qa-db-fra.com

Arguments multiples dans l'appel de fonction vs tableau unique

J'ai une fonction qui prend un ensemble de paramètres, puis les applique en tant que conditions à une requête SQL. Cependant, alors que je favorisais un tableau d'arguments unique contenant les conditions elles-mêmes:

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;
        }
    }
}

Mon collègue a préféré plutôt énumérer tous les arguments explicitement:

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

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

Son argument était qu'en listant les arguments de manière explicite, le comportement de la fonction devient plus apparent - au lieu d'avoir à fouiller dans le code pour découvrir quel était l'argument mystérieux $param.

Mon problème était que cela devient très verbeux lorsqu'il s'agit de nombreux arguments, comme 10+. Y a-t-il une pratique préférée? Mon pire scénario serait de voir quelque chose comme ceci:

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

24
xiankai

À mon humble avis, votre collègue a raison pour l'exemple ci-dessus. Votre préférence peut être concise, mais elle est également moins lisible et donc moins maintenable. Posez-vous la question de savoir pourquoi s'embêter à écrire la fonction en premier lieu, qu'est-ce que votre fonction "apporte à la table" - je dois comprendre ce qu'elle fait et comment elle le fait, en détail, juste pour l'utiliser. Avec son exemple, même si je ne suis pas un programmeur PHP, je peux voir suffisamment de détails dans la déclaration de fonction pour ne pas me préoccuper de son implémentation.

En ce qui concerne un plus grand nombre d'arguments, cela est normalement considéré comme une odeur de code. En général, la fonction essaie d'en faire trop? Si vous trouvez un réel besoin pour un grand nombre d'arguments, il est probable qu'ils sont liés d'une manière ou d'une autre et appartiennent ensemble à une ou quelques structures ou classes (peut-être même un tableau d'éléments connexes tels que des lignes dans une adresse). Cependant, le passage d'un tableau non structuré ne résout rien aux odeurs de code.

27
mattnz

Ma réponse est plus ou moins indépendante de la langue.

Si le seul but de regrouper des arguments dans une structure de données complexe (table, enregistrement, dictionnaire, objet ...) est de les transmettre dans leur ensemble à une fonction, mieux vaut l'éviter. Cela ajoute une couche de complexité inutile et rend votre intention obscure.

Si les arguments groupés ont un sens par eux-mêmes, alors cette couche de complexité aide à comprendre l'ensemble du design: nommez-le plutôt couche d'abstraction.

Vous pouvez constater qu'au lieu d'une douzaine d'arguments individuels ou d'un grand tableau, la meilleure conception est de deux ou trois arguments regroupant chacun des données corrélées.

4
mouviciel

Dans votre cas, je préférerais la méthode de votre collègue. Si vous écriviez des modèles et que j'utilisais vos modèles pour les développer. Je vois la signature de la méthode de votre collègue et je peux l'utiliser immédiatement.

Pendant ce temps, je devrais passer par l'implémentation de votre fonction searchQuery pour voir quels paramètres sont attendus par votre fonction.

Je préférerais votre approche uniquement dans le cas où le searchQuery est limité à la recherche uniquement dans une seule table, donc il n'y aura pas de jointures. Dans ce cas, ma fonction ressemblerait à ceci:

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

Donc, je sais immédiatement que les éléments du tableau sont en fait les noms de colonnes d'un table particulier que la classe ayant cette méthode représente dans votre code.

1
Ozair Kafray

Faites les deux, en quelque sorte. array_merge permet une liste explicite en haut de la fonction, comme votre collègue l'aime, tout en évitant que les paramètres ne deviennent trop lourds, comme vous préférez.

Je suggère également fortement d'utiliser la suggestion de @ chiborg dans les commentaires de la question - c'est beaucoup plus clair ce que vous avez l'intention.

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

Vous pouvez également passer une chaîne ressemblant à une chaîne de requête et utiliser parse_str (car il semble que vous utilisiez PHP, mais d'autres solutions sont probablement disponibles dans d'autres langues) pour le traiter dans un tableau à l'intérieur de la méthode:

/**
 * 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 ...;
}

et l'appelle comme

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

Vous pouvez utiliser http_build_query pour convertir un tableau associatif en une chaîne (l'inverse que parse_str Est-ce que).

0