题
我一直在努力理解一段时间以来一直在努力理解的东西,但是我想学习如何将它们用于设置以及PHP中的类似物品。
我终于找到了一个声称确实做到这一点的课程,而且我能说的是,它似乎有效,但是我不确定这是否是最好的方法。我将在下面的示例代码中发布类文件,以显示工作顺序。
如果您有经验,请告诉我是否可以改进,以进行性能或其他任何事情。我真的很想学习这件事,而且我一直在阅读它,但是到目前为止,我很难掌握。
班上...
<?php
class bitmask
{
/**
* This array is used to represent the users permission in usable format.
*
* You can change remove or add valuesto suit your needs.
* Just ensure that each element defaults to false. Once you have started storing
* users permsisions a change to the order of this array will cause the
* permissions to be incorectly interpreted.
*
* @type Associtive array
*/
public $permissions = array(
"read" => false,
"write" => false,
"delete" => false,
"change_permissions" => false,
"admin" => false
);
/**
* This function will use an integer bitmask (as created by toBitmask())
* to populate the class vaiable
* $this->permissions with the users permissions as boolean values.
* @param int $bitmask an integer representation of the users permisions.
* This integer is created by toBitmask();
*
* @return an associatve array with the users permissions.
*/
public function getPermissions($bitMask = 0)
{
$i = 0;
foreach ($this->permissions as $key => $value)
{
$this->permissions[$key] = (($bitMask & pow(2, $i)) != 0) ? true : false;
// Uncomment the next line if you would like to see what is happening.
//echo $key . " i= ".strval($i)." power=" . strval(pow(2,$i)). "bitwise & = " . strval($bitMask & pow(2,$i))."<br>";
$i++;
}
return $this->permissions;
}
/**
* This function will create and return and integer bitmask based on the permission values set in
* the class variable $permissions. To use you would want to set the fields in $permissions to true for the permissions you want to grant.
* Then call toBitmask() and store the integer value. Later you can pass that integer into getPermissions() to convert it back to an assoicative
* array.
*
* @return int an integer bitmask represeting the users permission set.
*/
function toBitmask()
{
$bitmask = 0;
$i = 0;
foreach ($this->permissions as $key => $value)
{
if ($value)
{
$bitmask += pow(2, $i);
}
$i++;
}
return $bitmask;
}
}
?>
如何将权限设置/保存为BitMask值?
<?php
/**
* Example usage
* initiate new bitmask object
*/
$perms = new bitmask();
/**
* How to set permissions for a user
*/
$perms->permissions["read"] = true;
$perms->permissions["write"] = true;
$perms->permissions["delete"] = true;
$perms->permissions["change_permissions"] = true;
$perms->permissions["admin"] = false;
// Converts to bitmask value to store in database or wherever
$bitmask = $perms->toBitmask(); //in this example it is 15
$sql = "insert into user_permissions (userid,permission) values(1,$bitmask)";
echo $sql; //you would then execute code to insert your sql.
?>
根据位值返回每个数组项目的true/false的示例。
<?php
/**
* Example usage to get the bitmask value from database or session/cache.... then put it to use.
* $permarr returns an array with true/false for each array value based on the bit value
*/
$permarr = $perms->getPermissions($bitmask);
if ($permarr["read"])
{
echo 'user can read: <font color="green">TRUE</font>';
}
else {
echo 'user can read: <font color="red">FALSE</font>';
}
//user can WRITE permission
if ($permarr["write"])
{
echo '<br>user can write: <font color="green">TRUE</font>';
}
else {
echo '<br>user can write: <font color="red">FALSE</font>';
}
?>
解决方案
位字段是一个非常方便,有效的工具,用于处理标志或任何一组布尔值。
要了解它们,您首先需要知道二进制数字如何工作。之后,您应该检查手动条目 钻头操作员 并确保您知道位和左/右移动的工作方式。
一个位字段不过是整数值。假设我们的位字段的大小是固定的,只有一个字节。计算机与二进制数字一起工作,因此,如果我们的数字值为 29
, ,您实际上会发现 0001 1101
在内存中。
使用位和((&
)和位或(|
)您可以读取并单独设置数字的每个位。他们都将两个整数作为输入,并单独执行和/或在每个位上执行和/或。
要读出您的电话号码的第一位,您可以做这样的事情:
0001 1101 (=29, our number)
& 0000 0001 (=1, bit mask)
= 0000 0001 (=1, result)
如您所见,您需要一个特殊的数字,只有我们感兴趣的位置设置,这就是所谓的“ bit mask”。在我们的情况下是 1
. 。要读出第二位,我们必须“按”位掩蔽中的一位数字。我们可以用左移动操作员来做到这一点($number << 1
)或通过将我们的两个乘以两个。
0001 1101
& 0000 0010
= 0000 0000 (=0, result)
您可以在我们的电话号码中完成此操作。二进制和我们的数字和位掩码的二进制会导致零,这意味着位不是“设置”,或者是非零整数,这意味着钻头已设置。
如果要设置其中一个,则可以使用位或:
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)
起初,它看起来可能有些隐秘,但实际上很容易。
到目前为止,您可能发现BIT字段是一种相当低级的技术。这就是为什么我建议不要在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个值。
其他提示
这是定义位掩码的方法。
// the first mask. In binary, it's 00000001
define('BITWISE_MASK_1', 1 << 0); // 1 << 0 is the same as 1
// the second mask. In binary, it's 00000010
define('BITWISE_MASK_2', 1 << 1);
// the third mask. In binary, it's 00000100
define('BITWISE_MASK_3', 1 << 2);
要检查是否存在BitMask(在函数参数中,在这种情况下),请使用位和操作员。
function computeMasks($masks) {
$masksPresent = array();
if ($masks & BITWISE_MASK_1)
$masksPresent[] = 'BITWISE_MASK_1';
if ($masks & BITWISE_MASK_2)
$masksPresent[] = 'BITWISE_MASK_2';
if ($masks & BITWISE_MASK_3)
$masksPresent[] = 'BITWISE_MASK_3';
return implode(' and ', $masksPresent);
}
这是因为当您或两个字节时(例如, 00000001
和 00010000
),您将两者聚集在一起: 00010001
. 。如果您和结果和原始面具(00010001
说, 00000001
),如果有的话,您会得到一个面具(在这种情况下 00000001
)。否则,您将获得零。