當前位置: 首頁> 最新文章列表> 封裝一個支持多種格式的通用打包函數

封裝一個支持多種格式的通用打包函數

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函數實現對等的解包功能。