PHP左移运算符<<移的是整数的二进制位,操作对象和结果始终为整数,非整数会先强制转为int;左移n位等价于乘以2^n(不溢出时),但受平台位宽和符号位影响,可能产生负数或溢出。

PHP左移运算符<<到底在移什么
它移的是整数的二进制位,不是字符串,也不是浮点数。传入非整数时,PHP会先用(int)强制转换——这意味着3.9 << 1等价于3 << 1,结果是6;而null << 2变成0 << 2,结果还是0。
左移n位,等价于乘以2<sup>n</sup>(仅当不溢出时成立)。但要注意:PHP整数有符号,且取决于平台(32位/64位),左移可能触发溢出,导致符号位翻转。比如在32位系统上,0x40000000 << 1会变成负数。
为什么1 << 31在不同PHP版本结果不一样
核心原因是整数大小和符号处理差异。32位系统中,int是32位有符号类型,最高位是符号位。1 << 31把1推到符号位,结果为-2147483648;而在64位系统中,同样操作得到的是正数2147483648(因为还有足够高位)。
- 用
PHP_INT_SIZE确认当前整数宽度(4=32位,8=64位) - 避免依赖具体值做位掩码,改用
0x7FFFFFFF这类显式十六进制常量 - 若需无符号语义,先用
unpack('L', pack('l', $val))绕过符号解释(但性能差,慎用)
<<和*哪个更快?什么时候不能互换
现代PHP(7.4+)JIT或OPcache下,两者编译后几乎没差别;纯解释执行时左移略快,但差距可忽略。真正不能互换的场景是:需要精确位布局时——比如构造协议头、解析硬件寄存器、实现哈希算法中的位旋转。
立即学习“PHP免费学习笔记(深入)”;
例如:$flag = 1 << 5表示“第5位为1”,而$flag = 1 * 32只保证数值相等,丢失位意图,后续用$flags & $flag判断时逻辑不变,但可读性和维护性断层。
- 算术运算优先用
*,语义清晰 - 位操作场景必须用
<<,哪怕只是1 << $n -
2 ** $n是幂运算,类型为float,和<<行为完全不同,别混用
常见错误:用<<处理大数或字符串
这是最常踩的坑:"123" << 2不会报错,但先转成123再左移,结果是492;而"abc" << 1转成0,结果恒为0。更隐蔽的是从$_GET取值未过滤,$_GET['shift']可能是"2a",强制转int得2,表面正常,实则丢失校验。
- 始终对输入做
is_int()或filter_var($n, FILTER_VALIDATE_INT) - 移位数建议限制在
0到PHP_INT_SIZE * 8 - 1之间,超出结果未定义 - 调试时用
decbin()看原始位模式,比直接echo数值更可靠
位运算不难,难的是记住它永远工作在整数的二进制补码表示上,而PHP的类型转换又太“热心”。一旦离开整数上下文,<<就不再是你认为的那个左移了。



















