当前位置: 首页> 最新文章列表> 封装一个支持多种格式的通用打包函数

封装一个支持多种格式的通用打包函数

M66 2025-05-29

在PHP开发中,有时我们需要将多个数据按指定格式打包成二进制字符串,方便网络传输或文件存储。PHP提供的pack函数可以实现这个需求,但它需要传入复杂的格式字符串,不同场景格式差异较大。本文将介绍如何用pack函数封装一个支持多种格式的通用打包函数,提升代码的复用性和灵活性。


一、pack函数简介

pack函数的基本语法是:

string pack(string $format, mixed ...$values)
  • $format 指定格式,如C表示无符号字符,n表示16位大端字节序整型等。

  • $values 是对应格式的数据。

例如,将两个无符号字符和一个16位大端整数打包:

$data = pack('CCn', 0x01, 0x02, 0x1234);

二、设计通用打包函数的思路

我们希望封装的函数:

  • 接受格式字符串和对应的值数组。

  • 自动根据格式字符串将值逐个打包。

  • 支持常见格式类型,且方便扩展。

  • 处理参数和格式不匹配的错误。

示例函数签名:

function universalPack(string $format, array $values): string

三、实现代码示例

下面是一个基础实现,支持CnNa等格式:

function universalPack(string $format, array $values): string {
    $result = '';
    $formatLength = strlen($format);
    $valueIndex = 0;

    for ($i = 0; $i < $formatLength; $i++) {
        $char = $format[$i];
        $repeat = 1;

        // 检测是否有重复数量,如a4、C2等
        if (isset($format[$i + 1]) && ctype_digit($format[$i + 1])) {
            $repeat = (int)$format[$i + 1];
            $i++;
        }

        for ($r = 0; $r < $repeat; $r++) {
            if (!isset($values[$valueIndex])) {
                throw new InvalidArgumentException("值数量与格式不匹配");
            }
            $value = $values[$valueIndex];
            $valueIndex++;

            switch ($char) {
                case 'C': // 无符号字符
                    $result .= pack('C', $value);
                    break;
                case 'n': // 16位大端字节序
                    $result .= pack('n', $value);
                    break;
                case 'N': // 32位大端字节序
                    $result .= pack('N', $value);
                    break;
                case 'a': // NUL填充字符串,长度由repeat决定
                    if ($repeat < 1) {
                        throw new InvalidArgumentException("a格式需要指定长度");
                    }
                    $str = str_pad(substr($value, 0, $repeat), $repeat, "\0");
                    $result .= $str;
                    // a格式一次处理所有repeat,valueIndex不递增
                    $valueIndex--;
                    break;
                default:
                    throw new InvalidArgumentException("不支持的格式字符: $char");
            }
        }
    }

    return $result;
}

四、使用示例

假设要打包一个数据包,结构为:

  • 1字节命令号(C

  • 2字节数据长度(n

  • 4字节数据ID(N

  • 10字节数据内容(字符串,a10

调用示例:

$command = 0x01;
$length = 14;
$dataId = 123456;
$content = "hello";

$packed = universalPack('CnNa10', [$command, $length, $dataId, $content]);
echo bin2hex($packed);

输出为:

01000e0001e24068656c6c6f0000000000

五、总结

  • pack函数很强大,但直接使用时格式与值容易出错。

  • 封装一个通用的universalPack函数,简化多格式数据的打包工作。

  • 函数可以根据实际需求继续增强,比如支持更多格式,支持小端序等。

  • 实际项目中,也可以结合unpack函数实现对等的解包功能。