使用字符串拼接代替pack()
当需要打包字节时,可以通过使用chr()
、拼接符号.
以及foreach
循环来生成打包后的二进制数据(字符串):
packed = "";
foreach ( $a as $byte ) {
$packed .= chr( $byte );
}
在原始问题中,$a
是源数组,$packed
是存储在字符串变量中的生成的二进制数据。
基准测试
在编写本文时,已经有5种不同的工作解决方案,因此值得进行基准测试,以防需要打包的数据量很大。
我使用了1048576个元素的数组来测试这五种情况,以生成1 MB的二进制数据。我测量了执行时间和消耗的内存。
测试环境:PHP 5.6.30
- Mac OS X
- 2.2 GHz Intel Core I7
(当然只使用了单个核心)
// pack with ... operator: 57 ms - 1.3 MB
// string concatentation: 197 ms - 1.3 MB
// call_user_func_array: 249 ms - 1.5 MB
// multiple pack: 298 ms - 1.3 MB
// array_reduce: 39114 ms - 1.3 MB
直接使用
...
运算符与
pack
函数结合是目前最快的解决方案(
已接受答案)。
如果没有
...
可用(PHP 5.6之前的版本),则由
此答案提出的解决方案(字符串连接)是最快的。
每种情况的内存使用几乎相同。
如果有人感兴趣,我会发布测试代码。
<?php
function milliseconds() {
$mt = explode(' ', microtime());
return ((int)$mt[1]) * 1000 + ((int)round($mt[0] * 1000));
}
$test = $argv[ 1 ];
$arr = array();
for( $i = 0; $i < 1024 * 1024; $i++ )
{
$arr[] = rand( 0, 255 );
}
$ms0 = milliseconds();
$mem0 = memory_get_usage( true );
if( $test == '1' )
{
$data = "";
foreach ( $arr as $byte ) {
$data .= chr( $byte );
}
$test = "string concatentation";
}
if( $test == '2' )
{
$data = call_user_func_array("pack", array_merge(array("c*"), $arr));
$test = "call_user_func_array";
}
if( $test == '3' )
{
$data = pack("c*", ...$arr);
$test = "pack with ... operator";
}
if( $test == '4' )
{
$data = array_reduce($arr, function($carry, $item) { return $carry .= pack('c', $item); });
$test = "array_reduce";
}
if( $test == '5' )
{
$data = "";
foreach ($arr as $item) $data .= pack("c", $item);
$test = "multiple pack";
}
$ms = milliseconds() - $ms0;
$mem = round( ( memory_get_usage( true ) - $mem0 ) / ( 1024 * 1024 ), 1 );
echo "$test: $ms ms; $mem MB\n";