PHP按位或|的正确输入类型必须是整数,否则会静默转成0;字符串如'READ'|'WRITE'结果为0,常量未定义时如MSG_OOB|MSG_DONTWAIT会变成0|MSG_DONTWAIT,导致意外行为。

PHP按位或|的正确输入类型是什么
必须是整数,否则会静默转成0。比如'READ' | 'WRITE'结果是0,因为字符串被强制转为0 | 0;12 | '5'也是12 | 0,得12——这不是你想要的。
常见错误现象:socket_send($sock, $buf, $len, MSG_OOB | MSG_DONTWAIT)中如果MSG_OOB没定义或拼错,整个表达式就变成0 | MSG_DONTWAIT,可能意外开启非预期 flag。
- 检查常量是否已定义:
defined('MSG_OOB') || die('MSG_OOB missing') - 调试时直接
var_dump(MSG_OOB, MSG_DONTWAIT, MSG_OOB | MSG_DONTWAIT),别只看最终结果 - 用
intval()兜底不保险:它不能修复语义错误,比如把字符串'10'转成10,但10未必是你想表示的那个 flag
什么时候该用|而不是||
|是位运算符,||是逻辑或——它们根本不是一回事。写$flags = $a || $b只会返回true或false,完全没法组合权限或 socket flag。
典型误用:if ($userPerm | READ)看起来像在判断权限,其实它永远返回非零整数(真值),但if ($userPerm & READ)才是正确判断方式。
立即学习“PHP免费学习笔记(深入)”;
-
|用于“叠加”多个独立标志位,如E_ALL | E_STRICT -
||用于条件分支合并:if ($a === null || $b === null) - 优先级差异极大:
$a = 1 | 2 + 3等价于$a = 1 | (2 + 3);而$a = 1 || 2 + 3先算1 || 5得true,再赋值给$a(即1)
组合 flag 时|的实际写法和陷阱
PHP 中很多扩展(如error_reporting、stream_context_create、socket_send)都依赖|来传多个 flag。关键是每个 flag 必须是 2 的幂(即二进制只有一位是 1),否则位会重叠。
例如:SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK可行,因为它们分别是1、0x200000、0x80000;但若自定义FLAG_A = 3、FLAG_B = 5,FLAG_A | FLAG_B是7,后续用&判断时无法区分是 A+B 还是另一个单独 flag。
- 定义 flag 时坚持用左移:
define('READ', 1 、<code>define('WRITE', 1 、<code>define('EXEC', 1 - 避免魔法数字混用:
16 | 32不如FLAG_ASYNC | FLAG_URGENT可读 - 注意符号扩展:负数参与
|运算时,补码参与计算,结果可能出人意料,尽量只对无符号整数或已知范围的正整数使用
|运算后怎么验证是否生效
不能靠if ($flags | SOME_FLAG),这永远为真;也不能用==比较,因为组合值不等于单个 flag。
正确验证方式只有一种:用&测试某一位是否被置起。比如设$opt = SOCK_STREAM | SOCK_NONBLOCK,要确认SOCK_NONBLOCK是否在其中,必须写$opt & SOCK_NONBLOCK,结果非零即存在。
- 批量验证可用循环:
foreach ([SOCK_STREAM, SOCK_NONBLOCK] as $f) { if ($opt & $f) echo "has $f\n"; } - 调试时别省括号:
var_dump(($opt & SOCK_NONBLOCK) !== 0)比var_dump($opt & SOCK_NONBLOCK)更直观 - 注意
0的特殊性:$opt & 0永远是0,哪怕$opt很大——所以 flag 值绝不能为 0
&而非|或||——这三个点漏掉任意一个,问题就藏得又深又静。



















