PHP 将数组传递给 pack() 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29919260/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 00:39:54  来源:igfitidea点击:

PHP Passing an array to pack() function

phparrayspack

提问by Paolo

pack()syntax is (from http://php.net/manual/en/function.pack.php)

pack()语法是(来自http://php.net/manual/en/function.pack.php

string pack ( string $format [, mixed $args [, mixed $... ]] )

string pack ( string $format [, mixed $args [, mixed $... ]] )

so assuming I need to pack three bytes

所以假设我需要打包三个字节

$packed = pack( "c*", 65, 66, 67 );

$packed = pack( "c*", 65, 66, 67 );

But what if I have to pack an arbitrary number of bytes?

但是如果我必须打包任意数量的字节怎么办?

They could coveniently be stored into an array so I naively tried

它们可以方便地存储到数组中,所以我天真地尝试

$a = array( 65, 66, 67 );
$packed = pack( "c*", $a );

But it doesn't work.

但它不起作用。

Is there a way to make pack()work with an array ?

有没有办法pack()使用数组?

回答by Alex Howansky

At little late to the party, but for future reference, you can use the new ...operator (v5.6+) to explode the array inline:

聚会有点晚了,但为了将来参考,您可以使用 new...运算符 (v5.6+) 内联分解数组:

$packed = pack("c*", ...$a);

回答by inquam

You could create your own function array_packthat internally calls packusing the call_user_funcor the call_user_func_arrayfunctions so you can pass the correct number of parameters to it.

您可以使用call_user_funccall_user_func_array函数创建自己的array_pack内部调用函数,以便向其传递正确数量的参数。pack

Something like this could probably work (not tested though... But you get the general idea)

像这样的东西可能可以工作(虽然没有测试......但你明白了一般的想法)

function array_pack(array $arr) {
  return call_user_func_array("pack", array_merge(array("c*"), $arr));
}

回答by Paolo

use string concatenation instead of pack()

使用字符串连接代替 pack()

When packing bytesthe packed binary data (string) may be produced by simply using chr(), concatenation .and a foreachloop:

打包字节时,可以通过简单地使用chr()、连接.foreach循环来生成打包的二进制数据(字符串):

packed = "";
foreach ( $a as $byte ) {
    $packed .= chr( $byte );
}

Where $ais the source array and $packedis the produced binary data stored in a string variable, as per the original question.

根据原始问题,$a源数组在哪里以及$packed生成的二进制数据存储在字符串变量中。



benchmark

基准

Having come, at the time of writing, with 5 different working solutions, it's worth doing a benchmark in case the amount of data to pack is huge.

在撰写本文时,有5 种不同的工作解决方案,如果要打包的数据量很大,则值得做一个基准测试。

I've tested the five cases with a 1048576 elements array in order to produce 1 MB of binary data. I measured execution time and consumed memory.

我已经使用 1048576 个元素数组测试了五种情况,以生成 1 MB 的二进制数据。我测量了执行时间并消耗了内存。

Testing environment: PHP 5.6.30- Mac OS X- 2.2 GHz Intel Core I7

测试环境:PHP 5.6.30- Mac OS X-2.2 GHz Intel Core I7

(only a single core is used of course)

当然只使用了一个核心

// 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

The ...operator used directly with the packfunction if by far the fastest solution (accepted answer)

如果迄今为止最快的解决方案(已接受的答案),则该...运算符直接与该pack函数一起使用

If ...is not available (PHP version prior to 5.6) the solution proposed by this answer(string concatentation) is the fastest.

如果...不可用(PHP 5.6 之前的版本),则此答案( string concatentation)提出的解决方案是最快的。

Memory usage is almost the same for every case.

每种情况的内存使用量几乎相同。

I post the test code if anyone interested.

如果有人感兴趣,我会发布测试代码。



<?php

// Return elapsed time from epoch time in milliseconds

function milliseconds() {
    $mt = explode(' ', microtime());
    return ((int)$mt[1]) * 1000 + ((int)round($mt[0] * 1000));
}



// Which test to run [1..5]

$test = $argv[ 1 ];



// Test 1024x1024 sized array

$arr = array();
for( $i = 0; $i < 1024 * 1024; $i++ )
{
    $arr[] = rand( 0, 255 );
}



// Initial memory usage and time

$ms0 = milliseconds();
$mem0 = memory_get_usage( true );



// Test 1: string concatentation

if( $test == '1' )
{
    $data = "";
    foreach ( $arr as $byte ) {
        $data .= chr( $byte );
    }

    $test = "string concatentation";
}



// Test 2: call_user_func_array

if( $test == '2' )
{
    $data = call_user_func_array("pack", array_merge(array("c*"), $arr));

    $test = "call_user_func_array";
}



// Test 3: pack with ... operator

if( $test == '3' )
{
    $data = pack("c*", ...$arr);

    $test = "pack with ... operator";
}



// Test 4: array_reduce

if( $test == '4' )
{
    $data = array_reduce($arr, function($carry, $item) { return $carry .= pack('c', $item); });

    $test = "array_reduce";
}



// Test 5: Multiple pack

if( $test == '5' )
{
    $data = "";
    foreach ($arr as $item) $data .= pack("c", $item);

    $test = "multiple pack";
}



// Output result

$ms = milliseconds() - $ms0;
$mem = round( ( memory_get_usage( true ) - $mem0 ) / ( 1024 * 1024 ), 1 );
echo "$test: $ms ms; $mem MB\n";

回答by Rafael Hernández

I use this function:

我使用这个功能:

private function pack_array($format, $arg)
{
    $result="";
    foreach ($arg as $item) $result .= pack ($format, $item);
    return $result;
}

回答by geca

Another option if you can't use ...operator:

如果您不能使用...运算符,另一种选择:

$packed = array_reduce($a, function($carry, $item) {
    return $carry .= pack('c', $item);
});