Bit Manipulation
debt(d7/e3/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints list phpstan as the tool, but automated detection is explicitly marked 'no'. PHPStan can catch type mismatches but won't flag misuse of | vs & for flag-checking or subtle bitmask logic errors — these typically surface only during code review or when bugs manifest in production (wrong error levels, incorrect PDO fetch modes, unexpected permission behaviour).
Closest to 'simple parameterised fix' (e3). The quick_fix describes replacing boolean column arrays or array_intersect checks with bitwise integer operations. This is more than a single-line swap (it may touch schema, queries, and flag definitions) but is generally contained within one component or feature area — not a cross-cutting refactor.
Closest to 'localised tax' (b3). The applies_to covers web and cli contexts broadly, but bitmask usage is typically isolated to specific permission systems, feature-flag modules, or calls to PHP stdlib functions like error_reporting and PDO. The rest of the codebase is largely unaffected unless bitmask integers are shared as a central permission model.
Closest to 'serious trap' (t7). The misconception field directly names the canonical wrong belief: developers assume bitmasks are only for low-level systems programming and misread PHP's own stdlib. The common_mistakes reinforce multiple dangerous confusions: using | instead of & for flag checks, misunderstanding falsy 0, confusing ~ with !, and integer overflow on 32-bit PHP. These contradict intuitions from boolean/array logic, earning a t7.
Also Known As
TL;DR
Explanation
Bitwise operators in PHP: & (AND), | (OR), ^ (XOR), ~ (NOT), << (left shift), >> (right shift). Common patterns: checking a bit (n & (1<<i)), setting a bit (n | (1<<i)), clearing a bit (n & ~(1<<i)), toggling a bit (n ^ (1<<i)). Applications: permission flags (user roles as bitmask), feature flags, fast powers of 2, parity checking, and space-efficient sets. Bitmasks are used in PHP's own API — error_reporting levels, PDO fetch modes, and PREG flags.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- Using | to check if a flag is set — use & for checking: if ($flags & MY_FLAG) not if ($flags | MY_FLAG).
- Not understanding that 0 is falsy — if ($flags & FLAG) is false when FLAG is not set AND when $flags is 0.
- Integer overflow with large bitmasks in 32-bit PHP — use PHP_INT_SIZE to check word size.
- Confusing ~ (bitwise NOT) with ! (logical NOT).
Avoid When
- Avoid bitmasks when the set of flags is large, changes often, or needs to be queried individually in SQL — a junction table is more maintainable.
- Do not use bitwise operators where boolean operators are intended — & vs && and | vs || have different short-circuit behaviour and precedence.
- Avoid bit manipulation in domain logic where clarity matters more than micro-optimisation — future maintainers will not thank you.
When To Use
- Use bitmasks to store multiple boolean flags in a single integer column — compact, fast to query, and easy to extend without schema changes.
- Apply bitwise operations for performance-critical tight loops: power-of-two checks, fast modulo, flag testing in inner loops.
- Use XOR for in-place swaps and simple checksums where readability is secondary to performance.
Code Examples
// Wrong operator for flag check — | always returns non-zero:
define('CAN_READ', 0b001); // 1
define('CAN_WRITE', 0b010); // 2
define('CAN_DELETE', 0b100); // 4
$permissions = CAN_READ; // User has read only
if ($permissions | CAN_WRITE) { // Bug: | always non-zero if either is set
allowWrite(); // Always executes!
}
// Correct bitmask operations:
$permissions = CAN_READ | CAN_WRITE; // 0b011 = 3
// Check:
if ($permissions & CAN_WRITE) { /* Has write permission */ }
if (!($permissions & CAN_DELETE)) { /* Does NOT have delete */ }
// PHP stdlib bitmask:
error_reporting(E_ALL & ~E_NOTICE); // All errors except notices
$stmt = $pdo->query($sql, PDO::FETCH_ASSOC | PDO::FETCH_UNIQUE);