编程 PHP 8.6 的 pack/unpack 端序修饰符:一个 l< 读取小端 int32,但要小心键名

2026-10-21 21:05:23

PHP 8.6 的 pack/unpack 端序修饰符:一个 l(大端)修饰符,直接写在格式码后面。

哪些格式码支持

整数码 s、l、q(有符号)与 S、L、Q(无符号)现在可以带端序修饰符;浮点码 f、d 同样支持。

对本身带固有端序的格式码使用这些修饰符会抛 ValueError,例如网络序的 n、v 这类码再追加 `` 就没有意义。

以前的写法

读一个带符号的小端 int32,得先按无符号读取,再自己判断符号位并做减法:

$v = unpack('V', $raw)[1];
if ($v >= 0x80000000) {
$v -= 0x100000000;
}

这只覆盖了 int32 一种宽度。换成 int64 就要改常量、改判断边界;字段一多,每个字段都得配一段位移和符号修正的代码,解析函数很容易写成一串特判。读一个有符号小端 int32,过去需要多次 unpack 再位移。

现在的写法

$raw = "\x01\x00\x00\x00";           // 小端 int32 = 1
var_dump(unpack('l 1]
var_dump(unpack('l 1]

浮点:

$bytes = "\x00\x00\x80\x3f";         // 小端 float 1.0
var_dump(unpack('f', 1.5);

pack('s', 1.5) 得到大端双精度。同一套修饰符在读写两侧通用,往返测试时不用再手写转换函数。

容易出错的地方:名字后缀会覆盖修饰符

注意键名规则的变化:unpack('s 1]

  • unpack('l 1]

如果代码里按 `$row[' int(1) }


验证不支持组合的错误类型:

```bash
php -r 'try { unpack("ngetMessage(); }'

验证读写往返:

php -r 'var_dump(bin2hex(pack("s<", -2)));'          # feff
php -r 'var_dump(unpack("s<", pack("s<", -2))[1]);'  # -2

同一版本的其他变更

PHP 8.6 还包含:clamp()、Time\Duration、Io\Poll、结构化流错误(StreamError 与 StreamErrorMode::Exception)、TLS 会话恢复与 0-RTT、readonly 属性默认值、PASSWORD 相关调整,以及 Session 默认值收紧。8.6.0 GA 计划在 2026-11-19,RC3 为 2026-10-08。

复制全文 生成海报 PHP 二进制协议 接口对接

推荐文章

程序员茄子在线接单