PHP Передача массива в функцию pack ()

pack() Синтаксис есть (от http://php.net/manual/en/function.pack.php)

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

при условии, что мне нужно собрать три байта

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

Но что, если мне нужно упаковать произвольное количество байтов?

Их удобно хранить в массиве, поэтому я наивно пытался

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

Но это не работает.

Есть ли способ сделать pack() работать с массивом?

4

Решение

Немного опоздал на вечеринку, но для дальнейшего использования, вы можете использовать новый ... оператор (v5.6 +), чтобы взорвать массив в строке:

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

Другие решения

Вы можете создать свою собственную функцию array_pack что внутренне вызывает pack с использованием call_user_func или call_user_func_array функции, чтобы вы могли передать ему правильное количество параметров.

Нечто подобное может, вероятно, сработать (хотя и не проверено … Но вы понимаете, в общем)

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

использовать конкатенацию строк вместо pack()

При упаковке байтов упакованные двоичные данные (строка) могут быть получены простым использованием chr()конкатенация . и foreach цикл:

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

куда $a это исходный массив и $packed является произведенными двоичными данными, сохраненными в строковой переменной, согласно оригинальному вопросу.


эталонный тест

Придя, на момент написания, с 5 разных рабочих решений, Стоит сделать тест на случай, если объем данных для упаковки огромен.

Я протестировал пять случаев с массивом из 1048576 элементов, чтобы получить 1 МБ двоичных данных. Я измерил время выполнения и израсходовал память.

Среда тестирования: PHP 5.6.30Mac OS X2.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) решение, предложенное этот ответ (string concatentation) самый быстрый.

Использование памяти практически одинаково для каждого случая.

Выкладываю тестовый код, если кому интересно.


<?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";
2

Я использую эту функцию:

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

Другой вариант, если вы не можете использовать ... оператор:

$packed = array_reduce($a, function($carry, $item) {
return $carry .= pack('c', $item);
});
0
По вопросам рекламы [email protected]