binario a decimal php
Mejores prácticas para indicadores de bits en PHP (7)
Una forma de almacenarlos en la base de datos es en un solo campo entero como banderas bit a bit.
Si quieres hacer esto, puedes usar los métodos de sobrecarga __get y __set para que puedas recuperar el campo y luego hacer la aritmética a nivel de bit según sea necesario.
Estoy escribiendo una pequeña aplicación en PHP + MySQL y he llegado al punto donde hay un objeto que tiene un par (8 hasta ahora pero no se espera que aumente) de indicadores asociados con él. Las banderas son muy poco relacionadas, aunque hay algunas combinaciones que no tendrían sentido. El objeto representa una fila en un DB (tiene algunos métodos para guardarlo / cargarlo también) por lo que la pregunta también se aplica a elegir un método de almacenamiento.
La pregunta es: ¿cómo representarlos mejor tanto en código como en DB? Puedo pensar de varias maneras:
Una forma de almacenarlos en la base de datos es en un solo campo entero como banderas bit a bit. En el lado de PHP, entonces puedo imaginar varias formas de representarlos:
- Simplemente exporte el valor entero y defina un par de constantes de bandera; Deje que cada lugar que necesita las banderas haga su propia magia bit a bit;
- Defina los métodos de clase
GetFlag()
,SetFlag()
yUnsetFlag()
que hacen la magia bit a bit en una variable entera privada; Estos métodos pasarían una de las constantes de indicador como parámetros. - Defina los métodos
GetFlagA()
,GetFlagB()
etc. (junto con las contrapartes Set and Unset); - Defina un grupo de variables miembro que representan una bandera; Configúrelos al cargar desde el DB y agrúpelos al guardarlos.
- Cree una variable miembro que sea una matriz de todos los valores de indicador. Use constantes predefinidas como índices de matriz para acceder a cada indicador. También llene / reúna la matriz al cargar / guardar.
Otra forma sería almacenarlos en el DB como campos BIT separados. En PHP que luego se traduciría a varias variables miembro. En mi humilde opinión, esto complicaría las consultas.
Y la última manera sería definir una tabla anotada para todos los indicadores y una tabla intermedia para la relación muchos-a-muchos entre los indicadores y los objetos originales. En mi humilde opinión, la más desordenada de todas las soluciones, teniendo en cuenta que habría solo como 3 tablas de lo contrario.
No he hecho mucho desarrollo de PHP, así que no sé cuál sería la mejor práctica. En C #, probablemente los almacenara como banderas bit a bit y creara propiedades que hagan la magia bit a bit en un entero privado. Pero PHP no tiene propiedades (estoy usando la última versión estable) ...
Me mantendría alejado de las operaciones bit a bit, ya que es muy difícil saber qué banderas se establecen mirando solo a la base de datos (a menos que intentes ser súper eficiente por algún motivo). Entre las otras dos opciones, creo que depende de cuánto significa cada una de estas banderas. Dado que ya hay 8 de ellos, me inclinaría hacia otra mesa con una relación de muchos a muchos entre ellos (lo siento por elegir tu menos favorito).
OK, después de pensar un poco más al respecto he decidido ir con una variable miembro por bandera. Pude haber usado el enfoque del método getter / setter, pero no los uso en ningún otro lugar en mi código, así que esto sería fuera de estilo. Además, de esta manera también abstraigo del método de almacenamiento de BD y luego puedo cambiarlo fácilmente si es necesario.
En cuanto a la base de datos, me quedaré con el entero bit a bit por ahora, principalmente porque ya casi termino con el software y ya no quiero cambiar eso. No cambia la legibilidad en absoluto.
Si realmente tiene que usar indicadores de bits, utilice una columna SET para almacenarlos en el DB, una matriz asociativa en el código y métodos para activar / desactivar los indicadores. Agregue métodos separados para convertir la matriz a / desde un único entero si lo necesita en ese formato.
No se gana nada con el uso de operadores de bits de bajo nivel, por lo que también podría hacer que el código sea legible.
Suponiendo que usa una versión de MySQL después de 5.0.5, podría definir la columna como BIT [ número de bits aquí ]. En cuanto al lado de PHP, probablemente vaya con el método Get / SetFlagA, Get / SetFlagB, no hay necesidad de un método desarmado, ya que puede simplemente tomar un booleano para el método set.
En su modelo , el objeto tiene 8 propiedades booleanas. Eso implica 8 columnas booleanas (TININT para MySQL) en su tabla de base de datos y 8 métodos getter / setter en su objeto. Simple y convencional.
Repensa tu enfoque actual. Imagina lo que dirá el próximo tipo que tiene que mantener esto.
CREATE TABLE mytable (myfield BIT(8));
OK, parece que tendremos algunos datos binarios aquí.
INSERT INTO mytable VALUES (b''00101000'');
Espera, alguien dime otra vez qué significa cada uno de esos 1s y 0s.
SELECT * FROM mytable;
+------------+
| mybitfield |
+------------+
| ( |
+------------+
¿Qué?
SELECT * FROM mytable WHERE myfield & b''00101000'' = b''00100000'';
WTF !? WTF !?
apuñala a sí mismo en la cara
- mientras tanto, en un universo alternativo donde las hadas juegan con unicornios y los programadores no odian a los DBA ... -
SELECT * FROM mytable WHERE field3 = 1 AND field5 = 0;
¡Felicidad y sol!
Codifiqué esta sencilla función para llenar el vacío entre PHP y MySQL ENUM:
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;
}
Uso:
// 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
Solo tiene que asegurarse de definir la lista enumerada en el mismo orden de MySQL ENUM.