2009-02-27 7 views
3

En travaillant sur une application particulière, je continue d'écrire des requêtes très similaires, encore et encore. Ils ne sont pas exactement les mêmes, mais sont de forme très similaire, et incorporés dans des morceaux de code presque identiques, par exemple.,Requêtes DRY et similaires

$Mysqli = new mysqli; 
if ($Stmt = $Mysqli->prepare("SELECT foo 
           FROM tblFoo 
           WHERE something = ?")) { 
    $Stmt->bind_param('s', $this->_something); 
    $Stmt->execute(); 
    if (0 != $Stmt->errno) 
     throw new Exception("blah, blah, blah"); 
    $Stmt->bind_result($foo); 
    while ($Stmt->fetch()){ 
     $this->_foos[] = new Foo($foo); 
    } 
    $Stmt->close(); 
    } else { 
     throw new Exception("blah, blah, blah");); 
    } 
} 

et plus tard, un autre endroit ...

$Mysqli = new mysqli; 
if ($Stmt = $Mysqli->prepare("SELECT bar, baz 
           FROM tblBar 
           WHERE somethingElse = ?")) { 
    $Stmt->bind_param('s', $this->_somethingElse); 
    $Stmt->execute(); 
    if (0 != $Stmt->errno) 
     throw new Exception("blah, blah, blah"); 
    $Stmt->bind_result($bar, $baz); 
    while ($Stmt->fetch()){ 
     // do something else with $bar and $baz 
    } 
    $Stmt->close(); 
    } else { 
     throw new Exception("blah, blah, blah");); 
    } 
} 

... et puis un autre, et d'ailleurs une autre ... etc.

Est-ce une véritable violation du SEC ? Il ne semble pas logique d'écrire une classe pour effectuer ce type de requête (avec des paramètres ou des paramètres de constructeur pour une table, une colonne, des variables liées, etc.) et ensuite de la réutiliser dans mon application. Mais en même temps, je ne peux pas ébranler ce sentiment lancinant que je me répète. Peut-être que c'est juste qu'il y a tellement de façons d'écrire une requête simple et qu'une certaine quantité de répétition comme celle-ci est à prévoir.

Pensées?

Répondre

1

Beaucoup de gens font exactement cela. Créez une classe représentant chaque table, qui hérite de la même classe. La classe de base peut gérer le chargement et l'enregistrement des données. Donc, si vous voulez charger les données, vous appelez simplement la méthode load. Et vous pouvez définir et accéder aux valeurs de champ par les propriétés des objets.

Il existe également des bibliothèques comme hibernate qui gèrent beaucoup de travail sale pour vous.

+0

@Kibbee - Merci. Je n'utiliserai pas Hibernate, mais j'ai créé une classe ActiveRecord, puis j'ai ajouté deux classes pour des tables spécifiques. – PartialOrder

1

Je dirais que c'était une violation. D'un coup d'œil à votre code (à moins que je ne manque quelque chose), ces deux déclarations sont identiques à l'exception des chaînes "foo" et "bar" (répétées plusieurs fois) et de votre logique métier réelle.

Au minimum, vous pouvez extraire cela. Plus précisément, toutes les chaînes SQL devraient probablement être extraites. Ils m'ont toujours semblé plus comme des données que du code. Si vous aviez un tableau de chaînes SQL, de tables, etc., est-ce que cela rendrait le refactoring plus évident?

(extraction des chaînes et autres données de votre code est une excellente façon de commencer un refactoring)

Une possibilité, si vous aviez un objet qui avait le nom de la table et une méthode contenant votre logique métier, vous pourriez passer dans un "processeur" avec tous les passe-partout (qui est tout le reste du code que vous avez là).

Je pense que cela pourrait faire sécher.

(PS. Préférez toujours la composition de l'héritage. Il n'y a aucun avantage à utiliser l'héritage sur une classe qui peut « exécuter » vos objets)

+0

@ Bill K. Ce fut un appel proche, mais je suis allé avec la réponse de Kibbee parce que c'est un peu plus proche de la façon dont j'ai fait face à cela. Vos commentaires ont également été très utiles, notamment en ce qui concerne l'extraction des chaînes de caractères comme première étape du refactoring. +1 merci! – PartialOrder

0

vous rencontrez l'un des premiers désirs à modularisation. :-)

Il existe deux solutions générales. La première consiste à faire abstraction de l'appel à toutes (ou à la plupart) des requêtes similaires. Et puis encore à un autre ensemble de requêtes. Et puis à l'autre. Etc. Malheureusement, cela se traduit par de nombreux blocs qui font la même chose: appeler une requête, vérifier les problèmes, assembler un ensemble de résultats, le renvoyer. C'est un DAL, mais seulement de toutes sortes. Cela ne change pas non plus.La deuxième solution consiste à faire abstraction du processus de création d'une requête et de renvoi du résultat, puis à extraire l'accès aux données par-dessus (ce qui signifie essentiellement que vous construisez quelque chose qui assemble SQL). Ceci est plus susceptible de devenir un ORM approprié plutôt qu'un simple DAL. Il est beaucoup plus facile de faire évoluer cela.