PHP中位标志的最佳实践

时间:2009-01-09 18:16:04

标签: php mysql flags

我在PHP + MySQL中编写了一个小应用程序,并且已经达到了一个对象,它有一对(有8个到目前为止但不会增加)与之关联的标志。这些标志几乎没有关系,尽管有些组合没有任何意义。该对象表示DB中的一行(有一些方法可以保存/加载它)所以问题也适用于选择存储方法。

问题是 - 如何在代码和数据库中最好地代表它们?我可以想到几种方法:

将它们存储在DB中的一种方法是在单个整数字段中作为按位标志。在PHP方面,我可以想象几种表示方式:

  • 只需导出整数值并定义几个标志常量;让每个需要旗帜的地方都有自己的按位魔法;
  • 定义在私有整数变量上执行按位魔术的类方法GetFlag()SetFlag()UnsetFlag();然后,这些方法将作为参数传递给其中一个标志常量。
  • 定义方法GetFlagA()GetFlagB()等(以及Set和Unset对应方);
  • 定义一组成员变量,每个变量代表一个标志;在从DB加载时设置它们并在保存时收集它们。
  • 创建一个成员变量,该变量是所有标志值的数组。使用预定义常量作为数组索引来访问每个标志。同时在加载/保存时填充/收集数组。

另一种方法是将它们作为单独的BIT字段存储在DB中。在PHP中,然后将转换为几个成员变量。恕我直言,这会使查询复杂化。

最后一种方法是为所有标志定义一个anothed表,并为标志和原始对象之间的多对多关系定义一个中间表。恕我直言,所有解​​决方案中最混乱的,考虑到只有3个表,否则。

我没有做太多的PHP开发,所以我不知道最佳实践是什么。在C#中,我可能会将它们存储为按位标志,并使属性在私有整数上执行按位魔术。但PHP没有属性(我使用的是最新的稳定版本)......

7 个答案:

答案 0 :(得分:35)

model中,对象有8个布尔属性。这意味着数据库表中有8个布尔(TINYINT for MySQL)列,对象中有8个getter / setter方法。简单而传统。

重新思考你当前的做法。想象一下,下一个需要维护这件事的人会说些什么。

CREATE TABLE mytable (myfield BIT(8));

好的,看起来我们将在这里发生一些二进制数据。

INSERT INTO mytable VALUES (b'00101000');

等等,有人再次告诉我这些1和0中的每一个代表什么。

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

什么?

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

WTF!? WTF!?

刺穿脸上的自我


- 同时,在另一个宇宙中,仙女与独角兽玩耍,程序员不讨厌DBA ...... -

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

幸福和阳光!

答案 1 :(得分:2)

如果你真的必须使用位标志,那么使用SET列将它们存储在DB中,代码中的关联数组以及打开/关闭标志的方法。如果您需要以该格式使用,可以添加单独的方法将数组转换为单个整数。

使用低级位操作符无法获得任何好处,因此您也可以使代码可读。

答案 2 :(得分:1)

我编写了这个简单的函数来填补PHP和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;
}

用法:

// 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

您只需确保按照MySQL ENUM的相同顺序定义枚举列表。

答案 3 :(得分:0)

假设您在5.0.5之后使用MySQL版本,您可以将列定义为BIT [位数]。至于PHP方面,我可能会使用Get / SetFlagA,Get / SetFlagB方法,不需要一个unset方法,因为你只需要一个布尔值来设置set方法。

答案 4 :(得分:0)

我会远离按位操作,因为通过仅查看数据库来确定设置哪些标志变得非常困难(除非您出于某种原因试图提高效率)。在其他两个选项之间,我认为它取决于每个标志的含义。鉴于已经有8个,我会倾向于另一个桌子,他们之间有多对多的关系(抱歉选择你最不喜欢的)。

答案 5 :(得分:0)

  

将它们存储在数据库中的一种方法是   一个整数字段按位   标志。

如果你想这样做,可以使用__get和__set overload methods,这样你就可以简单地检索字段,然后根据需要进行逐位算术。

答案 6 :(得分:0)

好的,在考虑了更多关于它之后,我决定每个标志使用一个成员变量。我可以使用getter / setter方法,但我不会在我的代码中的任何其他地方使用它们,所以这将是不合时宜的。另外,这样我也可以从数据库存储方法中抽象出来,以后可以根据需要轻松更改。

至于DB - 我现在要继续使用按位整数 - 这主要是因为我差不多完成了软件并且不想再改变它了。它根本不会改变可读性。