Question

Je suis en train d’écrire une petite application en PHP + MySQL et suis arrivé au point où il existe un objet qui possède un couple (8 jusqu’à présent, mais qui ne devrait pas augmenter) de drapeaux qui lui sont associés. Les drapeaux ne sont pratiquement pas liés, bien que certaines combinaisons n’aient aucun sens. L'objet représente une ligne dans une base de données (possède également certaines méthodes pour l'enregistrer / la charger). La question s'applique donc également au choix d'une méthode de stockage.

La question est la suivante - comment mieux les représenter à la fois dans le code et dans la base de données? ? Je peux imaginer plusieurs méthodes:

Une façon de les stocker dans la base de données consiste à utiliser un seul champ entier sous forme d’indicateurs au niveau du bit. Du côté de PHP, je peux imaginer plusieurs façons de les représenter:

  • Exportez simplement la valeur entière et définissez un couple de constantes de drapeau; Laissez chaque endroit qui a besoin des drapeaux faire sa propre magie au niveau des bits;
  • Définissez les méthodes de classe GetFlag () , SetFlag () et UnsetFlag () qui effectue la magie des bits sur une variable entière privée; Ces méthodes seraient ensuite passées à l’une des constantes du drapeau en tant que paramètres.
  • Définissez les méthodes GetFlagA () , GetFlagB () , etc. (avec les contreparties Set et Unset);
  • Définissez un groupe de variables membres qui représentent chacune un indicateur; Configurez-les lors du chargement à partir de la base de données et rassemblez-les lors de la sauvegarde.
  • Créez une variable membre qui est un tableau de toutes les valeurs d'indicateur. Utilisez des constantes prédéfinies comme index de tableau pour accéder à chaque indicateur. Remplissez / rassemblez également le tableau lors du chargement / de la sauvegarde.

Une autre solution consisterait à les stocker dans la base de données sous forme de champs BIT distincts. En PHP, cela se traduirait alors par plusieurs variables membres. IMHO cela compliquerait les requêtes.

Et le dernier moyen serait de définir une table supplémentaire pour tous les indicateurs et une table intermédiaire pour les relations plusieurs à plusieurs entre les indicateurs et les objets d'origine. IMHO la solution la plus compliquée, sachant qu’il n’y aurait que 3 tables identiques.

Je n’ai pas fait beaucoup de développement PHP, donc je ne sais pas quelle serait la meilleure pratique. En C #, je les stockerais probablement sous forme d'indicateurs au niveau du bit et créerais des propriétés qui feraient la magie du bit sur un entier privé. Mais PHP n'a pas de propriétés (j'utilise la dernière version stable) ...

Était-ce utile?

La solution

Dans votre modèle , l'objet a 8 propriétés booléennes. Cela implique 8 colonnes booléennes (TINYINT for MySQL) dans votre table de base de données et 8 méthodes getter / setter dans votre objet. Simple et conventionnel.

Repensez votre approche actuelle. Imaginez ce que dira le prochain gars qui devra maintenir cette affaire.

CREATE TABLE mytable (myfield BIT(8));

OK, il semble que nous ayons des données binaires ici.

INSERT INTO mytable VALUES (b'00101000');

Attendez, quelqu'un me répète ce que chacun de ces 1 et 0 représente.

SELECT * FROM mytable;
+------------+
| mybitfield |
+------------+
| (          | 
+------------+

Quoi?

SELECT * FROM mytable WHERE myfield & b'00101000' = b'00100000';

WTF !? WTF!?

se blesse au visage

- Pendant ce temps, dans un univers alternatif où les fées jouent avec les licornes et les programmeurs ne détestent pas les DBA ... -

SELECT * FROM mytable WHERE field3 = 1 AND field5 = 0;

Bonheur et soleil!

Autres conseils

Si vous devez réellement utiliser des indicateurs de bits, utilisez une colonne SET pour les stocker dans la base de données, un tableau associatif dans le code et des méthodes pour activer / désactiver les indicateurs. Ajoutez des méthodes distinctes pour convertir le tableau en / à partir d'un entier unique si vous en avez besoin dans ce format.

Il n'y a rien à gagner à utiliser des opérateurs de bits de bas niveau, vous pouvez donc tout aussi bien rendre le code lisible.

J'ai codé cette fonction simple pour combler le fossé entre ENUMs PHP et MySQL:

function Enum($id)
{
    static $enum = array();

    if (func_num_args() > 1)
    {
        $result = 0;

        if (empty($enum[$id]) === true)
        {
            $enum[$id] = array();
        }

        foreach (array_unique(array_map('strtoupper', array_slice(func_get_args(), 1))) as $argument)
        {
            if (empty($enum[$id][$argument]) === true)
            {
                $enum[$id][$argument] = pow(2, count($enum[$id]));
            }

            $result += $enum[$id][$argument];
        }

        return $result;
    }

    return false;
}

Utilisation:

// sets the bit flags for the "user" namespace and returns the sum of all flags (15)
Enum('user', 'anonymous', 'registed', 'active', 'banned');

Enum('user', 'anonymous'); // 1
Enum('user', 'registed', 'active'); // 2 + 4 = 6
Enum('user', 'registed', 'active', 'banned'); // 2 + 4 + 8 = 14
Enum('user', 'registed', 'banned'); // 2 + 8 = 10

Vous devez simplement vous assurer de définir la liste énumérée dans le même ordre que MySQL ENUM.

En supposant que vous utilisiez une version de MySQL après la version 5.0.5, vous pourriez définir la colonne comme étant BIT [ nombre de bits ici ]. Pour ce qui est du côté PHP, je choisirais probablement l’approche Get / SetFlagA, Get / SetFlagB. Il n’est pas nécessaire de recourir à une méthode non définie car vous pouvez simplement prendre un booléen de la méthode set.

Je resterais à l'écart des opérations au niveau des bits car il devient très difficile de savoir quels indicateurs sont activés en ne consultant que la base de données (à moins que vous n'essayiez d'être super efficace pour une raison quelconque). Entre les deux autres options, cela dépend, selon moi, de la signification de chacun de ces drapeaux. Étant donné qu'il y en a déjà 8, je me pencherais vers une autre table avec une relation plusieurs à plusieurs entre eux (désolé d'avoir choisi votre moins préféré).

  

Une façon de les stocker dans la base de données consiste à   un seul champ entier au niveau du bit   drapeaux.

Si vous le souhaitez, vous pouvez utiliser les méthodes de surcharge de surcharge afin que vous puissiez simplement récupérer le champ, puis faire l’arithmétique au niveau des bits si nécessaire.

OK, après avoir réfléchi un peu plus à ce sujet, j’ai décidé d’utiliser une variable membre par drapeau. J'aurais pu utiliser l'approche de méthode getter / setter, mais je ne les utilise nulle part ailleurs dans mon code, ce qui serait désuet. De plus, cette façon de faire, j’abstiens aussi de la méthode de stockage de la base de données et que je peux facilement changer par la suite si nécessaire.

En ce qui concerne la base de données - je vais rester pour l’instant au nombre entier au niveau des bits - principalement parce que j’ai presque fini avec le logiciel et que je ne veux plus le changer. Cela ne change pas du tout la lisibilité.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top