PHP中用于设置的位掩码?

PHP中用于设置的位掩码?,php,bitmask,Php,Bitmask,位和位掩码是我一直在努力理解的东西,但我想学习如何在PHP中使用它们进行设置和类似的事情 我终于找到了一个声称能做到这一点的类,正如我所知,它似乎很有效,但我不确定这是否是最好的方法。我将发布下面带有示例代码的类文件,以按工作顺序显示它 如果您有经验,请告诉我是否可以改进性能或其他方面。我真的很想学习这一点,我一直在阅读,但到目前为止,这对我来说是一个很难掌握的问题 班级 <?php class bitmask { /** * This a

位和位掩码是我一直在努力理解的东西,但我想学习如何在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;
        }
    }
?>

如何将权限设置/保存为位掩码值

<?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>';
    }
?>

以下是如何定义位掩码

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

这是因为当您输入一个或两个字节(例如,
00000001
00010000
)时,您将这两个字节组合在一起:
0000001
。如果您将结果和原始掩码(
00010001
并说,
00000001
),如果掩码存在,您将得到一个掩码(在本例中为
00000001
)。否则,将得到零。

位字段通常是处理标志或任何布尔值集的非常方便和有效的工具

要理解它们,首先需要知道二进制数是如何工作的。之后,您应该查看上的手动条目,并确保知道按位and、OR和左/右移位的工作原理

位字段只不过是一个整数值。让我们假设我们的位字段的大小是固定的,只有一个字节。计算机使用二进制数,因此如果我们的数字的值是
29
,那么实际上你会在内存中找到
0001 1101

使用按位AND(
&
)和按位OR(
|
)可以分别读取和设置数字的每一位。它们都将两个整数作为输入,并对每个位分别执行and/OR运算

要读出数字的第一部分,您可以执行以下操作:

  0001 1101 (=29, our number)
& 0000 0001 (=1, bit mask)
= 0000 0001 (=1, result)

正如您所看到的,您需要一个特殊的数字,其中只设置了我们感兴趣的位,这就是所谓的“位掩码”。在我们的例子中,它是
1
。要读取第二位,我们必须将位掩码中的位向左“推”一位。我们可以使用左移位运算符(
$number)来实现这一点。虽然您发布了一个资源,这很好,但如果您提供一些与通过谷歌等方式遇到此问题的人相关的详细信息,那就更好了。或者,更简单地说:链接不是答案。@Brian:好的,回答添加。我之前有点犹豫,因为我不是(我现在仍然不是)100%确定这是他的要求。我知道这不是你要求的,但考虑到你正在将其保存到数据库中,并将其保存为单个值,我必须问,为什么?你已经使数据库中的列无法用于任何筛选。你关心空间吗?我不明白你为什么说该列无法使用。他这样做的方式他可以n通过这样做可以轻松检索具有读取权限的用户,例如:
selectuserid fromsuser\u permissions,其中(permission&1)=1
@florian不可用,但您是否更喜欢位掩码而不是带有
can\u-read
的列?我想我更喜欢后者,但对其他人的想法感兴趣…当然
can\u-read
会更明确,但如果您有更多设置,可能您不希望15列带有
can\u-boo
can\u>o
@florian我可能会表现出我的愚蠢,但一个位掩码不能只有8个开/关值吗?我已经玩了很多次了,它是完美的,令人惊讶的,我在网上找到的每一个使用pow(2,$I)的例子有人告诉我这不是正确的,也不是最好的,所以这真的很棒,非常感谢,我相信这会对其他人的反馈有所帮助:)。正如你所说的,我希望这也能帮助其他人,因为答案比预期的要长一点。另外,如果你想进一步改进示例,你应该替换
define()
s与
const
并可能实现一些automagic getter/setter或ArrayAccess以获得额外的awesomness。@svens这就是我想将其更改为更独立的,不确定ArrayAccess是什么意思though@jasondavis查看此手册页:。它使对象的行为类似于数组,因此您可以执行某些操作如
$bf[PERM\u READ]
获取值。
  0001 1101 (=29, our number)
& 0000 0001 (=1, bit mask)
= 0000 0001 (=1, result)
  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)
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();