我需要使用大的位掩码(~115 位)。存储是 mysql,我的 orm 是学说。在 PHP 方面,我编写了一个类来处理任何事情,并且知道我需要一个好的解决方案来存储并通过在 MySQL 中的位比较再次找到它。我的想法是使用四个整数列或两个 bigint。现在我需要一种映射(PHP Object <=> 2-4 Columns DB)。symfony2 中有什么我可以使用的吗?
1 回答
这并不经常这样做。很多时候会有 BIT 类型的单列(或 MySQL 上的 TINYINT)或将选项放在另一个表中并执行 oneToMany(这将使您的选项易于配置)。位掩码更容易出错,因此请确保您确实需要此解决方案。话虽如此,这是可以做到的:
首先是一些关于 MySQL 数据类型的信息。对于位掩码,无符号可能是要走的路。
TINYINT -> 0-255 = 256 combinations = log 256 / log 2 = 8 bits
SMALLINT -> 16 bits
MEDIUMINT -> 24 bits
INT -> 32 bits
BIGINT -> 64 int
那么对于 115 位,您对这些字段的最佳使用是什么?这是一个 NP 完全问题,您可以使用贪心算法。采纳您的建议,选择 4x INT 和 2x BIGINT。总共给了我 256 个可用位。这超出了您对 115 位的要求。对 256 位使用 4x BIGINT 会更有意义。但是,我无法将这些列合并为一个大数字,而且 BIGINT 甚至可能有问题。如 PHP 手册中所述:
The size of an integer is platform-dependent, although a maximum value of about two billion is the usual value (that's 32 bits signed). 64-bit platforms usually have a maximum value of about 9E18. PHP does not support unsigned integers. Integer size can be determined using the constant PHP_INT_SIZE, and maximum value using the constant PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.
为了安全起见(因为我不知道你的平台),我将只使用 INT 并使用其中的四个来给我 128 位。(您仍然需要检查这将如何解决不支持无符号整数的 32 位问题!)
这是一项默认功能,doctrine:generate:Entities 会为您提供:public function getColumn1() {}
但是,让您的其他对象访问这些未处理的原始数据似乎不是一个好主意。所以让我们为此制作自定义函数。
private function getBit($index) {
if (0 <= $index AND $index <= 31) {
return ($this->column1 >> $index) & 1;
} elseif (32 <= $index AND $index <= 63) {
$index -= 32;
return ($this->column2 >> $index) & 1;
} elseif (64 <= $index AND $index <= 95) {
$index -= 64;
return ($this->column3 >> $index) & 1;
} elseif (96 <= $index AND $index <= 127) {
$index -= 96;
return ($this->column4 >> $index) & 1;
}
}
private function setBit($index, $value) {
if (! is_bool($value)) \BadMethodCallException('value needs to be a boolean'); // A form of type checking to make the interface to the function more clearly
$value = (int)$value; // not sure if this is needed, just to make sure
if (0 <= $index AND $index <= 31) {
$this->column1 = ($this->column1 & ~(1 << $index)) | ($value << $index);
} elseif (32 <= $index AND $index <= 63) {
$index -= 32;
$this->column2 = ($this->column2 & ~(1 << $index)) | ($value << $index);
} elseif (64 <= $index AND $index <= 95) {
$index -= 64;
$this->column3 = ($this->column3 & ~(1 << $index)) | ($value << $index);
} elseif (96 <= $index AND $index <= 127) {
$index -= 96;
$this->column4 = ($this->column4 & ~(1 << $index)) | ($value << $index);
}
}
Column1 用于最低有效位,其他列添加更多最高有效位。现在我们已经有了处理原始位的低级函数,可以很容易地为您想要的属性使用普通的 getter 和设置。
public function setFlag4($value) {
$this->setBit(4, $value);
return $this;
}
public function getFlag4() {
return $this->getBit(4);
}
当然,您可以输入任何名称,例如hasBananas()
第 25 位,而不是 Flag4