利用二進制位運算設計權限系統,是經典且高效的方案。每個權限佔用一個二進制位(2 的 N 次方),通過位或(|)、位與(&)、位非(~)實現授權、檢查、撤銷,極其節省存儲且運算極快。
<?php
define('ADD', 1); // 0001 - 增加
define('UPD', 2); // 0010 - 修改
define('SEL', 4); // 0100 - 查詢
define('DEL', 8); // 1000 - 刪除
// 以此類推:16, 32, 64...
?>
每個權限二進制中僅有一個 1,互不干擾,組合時通過位運算即可。
|$a_access = ADD | UPD | SEL | DEL; // 1111 = 15,擁有全部權限
$b_access = ADD | UPD | SEL; // 0111 = 7,無刪除權限
$c_access = ADD | UPD; // 0011 = 3,僅增改
& ~$d_access = $c_access & ~UPD; // 0011 & 1101 = 0001,僅保留 ADD
&var_dump($b_access & ADD); // 1 (true) - 有增權限
var_dump($b_access & DEL); // 0 (false) - 無刪權限
將上述邏輯封裝為 Peak_Auth(權限)與 Peak_Role(角色),支持繼承、鏈式調用:
<?php
class Peak_Auth {
protected static $authCount = 0;
protected $authName, $authMessage, $authValue;
public function __construct($authName, $authMessage = '') {
$this->authName = $authName;
$this->authMessage = $authMessage;
$this->authValue = 1 << self::$authCount++; // 自動生成 2^N
}
private function __clone() {} // 禁止克隆
public function getAuthValue() { return $this->authValue; }
public function getAuthName() { return $this->authName; }
public function getAuthMessage() { return $this->authMessage; }
public function setAuthMessage($msg) { $this->authMessage = $msg; }
}
class Peak_Role {
protected $roleName, $authValue = 0, $parentRole;
public function __construct($roleName, Peak_Role $parentRole = null) {
$this->roleName = $roleName;
if ($parentRole) {
$this->parentRole = $parentRole;
$this->authValue = $parentRole->getAuthValue(); // 繼承父角色權限
}
}
protected function fetchParenAuthValue() {
if ($this->parentRole) $this->authValue |= $this->parentRole->getAuthValue();
}
public function allow(Peak_Auth $auth) { // 賦予權限
$this->fetchParenAuthValue();
$this->authValue |= $auth->getAuthValue();
return $this; // 鏈式調用
}
public function deny(Peak_Auth $auth) { // 禁止權限
$this->fetchParenAuthValue();
$this->authValue &= ~$auth->getAuthValue();
return $this;
}
public function checkAuth(Peak_Auth $auth) { // 檢查權限
return (bool)($this->authValue & $auth->getAuthValue());
}
public function getAuthValue() { return $this->authValue; }
}
?>
<?php
$read = new Peak_Auth('CanRead');
$write = new Peak_Auth('CanWrite');
$exe = new Peak_Auth('CanExe');
$user = new Peak_Role('User');
$admin = new Peak_Role('Admin', $user); // Admin 繼承 User 權限
$user->allow($read)->allow($write); // User: 讀+寫
$admin->allow($exe); // Admin: 繼承讀寫 + 執行
$admin->deny($write); // Admin: 禁止寫入
var_dump($admin->checkAuth($read)); // true
var_dump($admin->checkAuth($write)); // false
var_dump($admin->checkAuth($exe)); // true
?>
| 優點 | 缺點/限制 |
|---|---|
| 極低內存佔用(一個整數存所有權限) | 權限數受限於整型位數(32/64位) |
| 位運算極快,適合高頻檢查 | 不直觀,需封裝良好 API |
| 天然支持權限組合、繼承、撤銷 | 難以表達「上下文相關」權限(如:僅能編輯自己發布的文章) |
適合功能型權限控制(菜單訪問、操作按鈕顯示/隱藏),若涉及數據級/行級權限,建議結合 ACL 或 Policy 模式。