位字段是处理标志或任何布尔值集合的非常方便且高效的工具。
要理解它们,您首先需要了解二进制数的工作原理。之后,您应该查看手动条目按位运算符 http://php.net/manual/en/language.operators.bitwise.php并确保您知道按位“与”、“或”和左/右移位是如何工作的。
位字段只不过是一个整数值。假设我们的位字段的大小是固定的并且只有一个字节。计算机使用二进制数,所以如果我们的数字的值为29
,你实际上会发现0001 1101
记忆中。
使用按位与 (&
) 和按位或 (|
)您可以单独读出并设置数字的每一位。它们都采用两个整数作为输入,并对每一位单独执行 AND/OR。
要读出号码的第一位,您可以执行以下操作:
0001 1101 (=29, our number)
& 0000 0001 (=1, bit mask)
= 0000 0001 (=1, result)
正如您所看到的,您需要一个特殊的数字,其中仅设置我们感兴趣的位,这就是所谓的“位掩码”。在我们的例子中是1
。要读出第二位,我们必须将位掩码中的一位向左“推”一位。我们可以使用左移运算符($number << 1
) 或将 our 乘以二。
0001 1101
& 0000 0010
= 0000 0000 (=0, result)
您可以对我们数字中的每一位进行此操作。我们的数字和位掩码的二进制 AND 导致要么为零,这意味着该位没有“设置”,要么导致非零整数,这意味着该位已设置。
如果要设置其中一位,可以使用按位或:
0001 1101
| 0010 0000 (=32, bit mask)
= 0011 1101 (=29+32)
然而,当你想“清除”一点时,你就必须走不同的路。
更通用的方法是:
// To get bit n
$bit_n = ($number & (1 << $n)) != 0
// Alternative
$bit_n = ($number & (1 << $n)) >> $n
// Set bit n of number to new_bit
$number = ($number & ~(1 << $n)) | ($new_bit << $n)
乍一看可能有点神秘,但实际上很简单。
现在您可能已经发现位字段是一种相当低级的技术。这就是为什么我建议不要在 PHP 或数据库中使用它们。如果您想要一堆标志,那可能没问题,但对于其他任何事情,您真的不需要它们。
你发布的课程对我来说看起来有点特别。例如,类似的事情... ? true : false
是非常糟糕的做法。如果您想使用位字段,您最好定义一些常量并使用上述方法。想出一个简单的类并不难。
define('PERM_READ', 0);
define('PERM_WRITE', 1);
class BitField {
private $value;
public function __construct($value=0) {
$this->value = $value;
}
public function getValue() {
return $this->value;
}
public function get($n) {
return ($this->value & (1 << $n)) != 0;
}
public function set($n, $new=true) {
$this->value = ($this->value & ~(1 << $n)) | ($new << $n);
}
public function clear($n) {
$this->set($n, false);
}
}
$bf = new BitField($user->permissions);
if ($bf->get(PERM_READ)) {
// can read
}
$bf->set(PERM_WRITE, true);
$user->permissions = $bf->getValue();
$user->save();
我没有尝试这个答案的任何代码,但即使它不能开箱即用,它也应该让您开始。
请注意,每个位字段最多可包含 32 个值。