использовать конкатенацию строк вместо pack()
При упаковке байтов упакованные двоичные данные (строка) могут быть созданы простым использованием chr()
, конкатенации .
и цикла foreach
:
packed = "";
foreach ( $a as $byte ) {
$packed .= chr( $byte );
}
Где $a
— исходный массив, а $packed
— созданные двоичные данные, хранящиеся в строковой переменной, в соответствии с исходным вопросом.
ориентир
Имея на момент написания статьи 5 различных рабочих решений, стоит провести тест на случай, если объем данных для упаковки огромен.
Я протестировал пять случаев с массивом из 1048576 элементов, чтобы получить 1 МБ двоичных данных. Я измерил время выполнения и потребляемую память.
Среда тестирования: 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), решение, предложенное этим ответом ( 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";
person
Paolo
schedule
15.04.2018