标题: 如何用php更好的实现 0777这种二进制的集合标记
时间: 2022-08-29发布,2022-08-29修改
<?php
$map=[0=>"唱歌a",1=>"跳舞",2=>"洗澡",7=>'睡觉a',8=>'吃饭'];
$decNum=129; // 010000001 (len=9,max_index=8) ; result=["唱歌","吃饭"]
$bin= decbin($decNum);
$mapKeys=array_keys($map);
$maxIndex=$mapKeys;
ksort($maxIndex);
$maxIndex=array_pop($maxIndex)+1;
echo '转2进制(缩写):'.$bin."</br>";
echo '转2进制(补全最大位):'.sprintf("%0".$maxIndex."s",$bin)."</br>";
function strMethod($dec,$map){
//取最大位数+1
$mapKeys=array_keys($map);
$maxIndex=$mapKeys;
ksort($maxIndex);
$str= decbin($dec);
$result=[];
//吧 0b1000 反转为 0b0001 ,因为 mapkey的第0=> 是指 从右往左的 下标
$str=strrev($str);
for($i=0;$i<=strlen($str);$i++){
if(\in_array($i,$mapKeys) && intval($str[$i])===0b1){
$result[]=$map[$i];
}
}
return $result;
}
function bitOperation($dec,$map){
$mapKeys=array_keys($map);
$maxIndex=$mapKeys;
ksort($maxIndex);
$maxIndex=array_pop($maxIndex)+0b1;
/**
*
* array_filter结果是反转k=>v; { ["唱歌"]=> int(0) ["跳舞"]=> int(1) ["洗澡"]=> int(2) ["睡觉"]=> int(7) ["吃饭"]=> int(8) }
*
* array_filter(array,function($MapItemValue){
//return true 就是不过滤,false为过滤
//假设第1伦是 $MapItemValue=0 ; //(2== 0b10)
* 唱歌 0b0+0b1=0b1=1
0b 1
0b010000001
* result : &按位与 两个数二进制部分 相同索引的都是1才能 !=false (0b0),所以这个是1 >0
* 跳舞 0b01+0b01= 0b10=2
0b 10
0b010000001
* })
*/
return array_filter(array_flip($map),function($MapItemValue)use ($dec,$maxIndex){
// echo '本次 $MapItemValue='.sprintf("%0".$maxIndex."s",decbin(1<<$MapItemValue));
// echo ';dec='.sprintf("%0".$maxIndex."s",decbin($dec));
// echo ';&结果'. (decbin(1<<$MapItemValue)&$dec).';';
//这里犯错 (1<<$MapItemValue)&$dec!==0b00000; //这里会优先 $dec!=0b0001 然后在&
// echo ((1<<$MapItemValue)&$dec)!==0b00000;
// echo "<br>";
return ((1<<$MapItemValue)&$dec)!==0b00000;
});
}
$result1=strMethod($decNum,$map);
var_dump($result1);
echo "<br>";
$result2=bitOperation($decNum,$map);
var_dump(array_keys($result2));
『回复列表(17|显示机器人聊天)』
对于虎绿林的权限,我选择预定义常量 + 整数 + 位操作,因为权限的个数是固定的。
注意别用MySQL的bit
类型,那是自找麻烦(写SQL时有类型转换问题),使用int UNSIGNED
类型就可以避免,如果超过32位就用bigint UNSIGNED
。
--
-- 表的结构 `hu60_user`
--
CREATE TABLE `hu60_user` (
`uid` int(11) NOT NULL,
`name` varchar(16) CHARACTER SET utf8mb4 NOT NULL,
-- ……
`permission` int(10) UNSIGNED NOT NULL DEFAULT 0,
-- ……
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
https://gitee.com/hu60t/hu60wap6/blob/master/src/class/userinfo.php
https://github.com/hu60t/hu60wap6/blob/master/src/class/userinfo.php
<?php
/**
* 虎绿林WAP6 读取用户信息
*/
class userinfo implements ArrayAccess
{
// 权限列表开始
// 权限有两种,一种是管理员具有的管理权限,一种是用户被管理员设置的负面状态。
// 两者的作用完全不同,但是存储在一起,请注意区分。
/*** 管理员权限: 帖子编辑权限 */
const PERMISSION_EDIT_TOPIC = 1;
/*** 用户负面状态: 用户被禁止使用div和span标签
*
* 该状态未开放给版主,只有站长通过SQL才能设置该状态。
*/
const DEBUFF_UBB_DISABLE_STYLE = 2;
/*** 用户负面状态: 用户被禁言 */
const DEBUFF_BLOCK_POST = 4;
/*** 用户负面状态: 用户被禁止@他人 */
const DEBUFF_BLOCK_ATINFO = 8;
/*** 管理员权限: 设置禁言的权限 */
const PERMISSION_SET_BLOCK_POST = 16;
/*** 管理员权限: 帖子加精权限 */
const PERMISSION_SET_ESSENCE_TOPIC = 32;
/*** 用户负面状态: 用户发言需要审核 */
const DEBUFF_POST_NEED_REVIEW = 64;
/*** 管理员权限: 审核用户发言的权限 */
const PERMISSION_REVIEW_POST = 128;
// 权限列表结束
// ……
public function hasPermission($permission) {
if (NULL === self::$data['permission'][$this->uid]) {
$db = self::conn(true);
$sql = 'SELECT `permission` FROM `'.DB_A.'user` WHERE uid = ?';
$rs = $db->prepare($sql);
if (!$rs || !$rs->execute([$this->uid])) {
throw new UserException('数据库异常,无法读取权限信息!', 10500);
}
$data = $rs->fetch(db::num);
self::$data['permission'][$this->uid] = $data[0];
}
return (bool) ($permission & self::$data['permission'][$this->uid]);
}
public function addPermission($permission) {
unset(self::$data['permission'][$this->uid]);
$db = self::conn();
$sql = 'UPDATE `'.DB_A.'user` SET `permission` = `permission` | ? WHERE uid = ?';
$rs = $db->prepare($sql);
if (!$rs || !$rs->execute([(int)$permission, $this->uid])) {
throw new UserException('数据库异常,无法设置权限信息!', 11500);
}
}
public function removePermission($permission) {
unset(self::$data['permission'][$this->uid]);
$db = self::conn();
$sql = 'UPDATE `'.DB_A.'user` SET `permission` = `permission` & ~ ? WHERE uid = ?';
$rs = $db->prepare($sql);
if (!$rs || !$rs->execute([(int)$permission, $this->uid])) {
throw new UserException('数据库异常,无法设置权限信息!', 11500);
}
}
// ……
}
对于用户的爱好集合,我选择存成单独的表。
CREATE 爱好列表(
爱好id int,
爱好名称 varchar(255)
);
CREATE 用户的爱好(
uid int,
爱好id int
);
这样才方便对爱好列表进行动态更新。